[IMP] quality_control: black, isort

This commit is contained in:
ps-tubtim
2020-03-16 17:32:22 +07:00
committed by Stefano Consolaro
parent a834796aa0
commit a6f788f2d5
25 changed files with 878 additions and 684 deletions

View File

@@ -7,16 +7,13 @@
{
"name": "Quality control",
"version": "12.0.1.2.0",
"version": "13.0.1.0.0",
"category": "Quality control",
"license": "AGPL-3",
"summary": "Generic infrastructure for quality tests.",
"author": "OdooMRP team, "
"Odoo Community Association (OCA)",
"author": "OdooMRP team, " "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/manufacture/tree/12.0/quality_control",
"depends": [
"product",
],
"depends": ["product"],
"data": [
"data/quality_control_data.xml",
"security/quality_control_security.xml",
@@ -30,8 +27,6 @@
"views/product_template_view.xml",
"views/product_category_view.xml",
],
"demo": [
"demo/quality_control_demo.xml",
],
"demo": ["demo/quality_control_demo.xml"],
"installable": True,
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -10,17 +10,18 @@
<record id="qc_test_template_category_generic" model="qc.test.category">
<field name="name">Generic</field>
</record>
<record id="qc_test_template_category_referenced" model="qc.test.category">
<field name="name">Referenced</field>
</record>
<record forcecreate="True" id="decimal_quality_control" model="decimal.precision">
<record
forcecreate="True"
id="decimal_quality_control"
model="decimal.precision"
>
<field name="name">Quality Control</field>
<field name="digits">5</field>
</record>
</data>
<data>
<record id="seq_qc_inspection" model="ir.sequence">
<field name="name">Quality inspection</field>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<data noupdate="1">
<record model="qc.test" id="qc_test_1">
@@ -7,25 +7,21 @@
<field name="active" eval="True" />
<field name="category" ref="qc_test_template_category_generic" />
</record>
<record model="qc.test.question" id="qc_test_question_1">
<field name="name">Overall quality</field>
<field name="test" ref="qc_test_1" />
<field name="type">qualitative</field>
</record>
<record model="qc.test.question.value" id="qc_test_question_value_1">
<field name="name">Good</field>
<field name="ok" eval="True" />
<field name="test_line" ref="qc_test_question_1" />
</record>
<record model="qc.test.question.value" id="qc_test_question_value_2">
<field name="name">Bad</field>
<field name="ok" eval="False" />
<field name="test_line" ref="qc_test_question_1" />
</record>
<record model="qc.test.question" id="qc_test_question_2">
<field name="name">Size</field>
<field name="test" ref="qc_test_1" />
@@ -34,6 +30,5 @@
<field name="max_value" eval="10.0" />
<field name="uom_id" ref="uom.product_uom_unit" />
</record>
</data>
</odoo>

View File

@@ -14,4 +14,5 @@ class ProductCategory(models.Model):
qc_triggers = fields.One2many(
comodel_name="qc.trigger.product_category_line",
inverse_name="product_category",
string="Quality control triggers")
string="Quality control triggers",
)

View File

@@ -12,5 +12,7 @@ class ProductProduct(models.Model):
_inherit = "product.product"
qc_triggers = fields.One2many(
comodel_name="qc.trigger.product_line", inverse_name="product",
string="Quality control triggers")
comodel_name="qc.trigger.product_line",
inverse_name="product",
string="Quality control triggers",
)

View File

@@ -14,4 +14,5 @@ class ProductTemplate(models.Model):
qc_triggers = fields.One2many(
comodel_name="qc.trigger.product_template_line",
inverse_name="product_template",
string="Quality control triggers")
string="Quality control triggers",
)

View File

@@ -5,17 +5,18 @@
# 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, _
from odoo import _, api, exceptions, fields, models
from odoo.tools import formatLang
import odoo.addons.decimal_precision as dp
class QcInspection(models.Model):
_name = 'qc.inspection'
_description = 'Quality control inspection'
_inherit = ['mail.thread', 'mail.activity.mixin']
_name = "qc.inspection"
_description = "Quality control inspection"
_inherit = ["mail.thread", "mail.activity.mixin"]
@api.depends('inspection_lines', 'inspection_lines.success')
@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])
@@ -28,74 +29,106 @@ class QcInspection(models.Model):
"""
return list()
@api.depends('object_id')
@api.depends("object_id")
def _compute_product_id(self):
for i in self:
if i.object_id and i.object_id._name == 'product.product':
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)
string="Inspection number",
required=True,
default="/",
readonly=True,
states={"draft": [("readonly", False)]},
copy=False,
)
date = fields.Datetime(
string='Date', required=True, readonly=True, copy=False,
string="Date",
required=True,
readonly=True,
copy=False,
default=fields.Datetime.now,
states={'draft': [('readonly', False)]})
states={"draft": [("readonly", False)]},
)
object_id = fields.Reference(
string='Reference',
string="Reference",
selection=lambda self: self.object_selection_values(),
readonly=True, states={'draft': [('readonly', False)]},
ondelete="set null")
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",
oldname='product')
comodel_name="product.product",
compute="_compute_product_id",
store=True,
help="Product associated with the inspection",
oldname="product",
)
qty = fields.Float(string="Quantity", default=1.0)
test = fields.Many2one(
comodel_name='qc.test', string='Test', readonly=True)
test = fields.Many2one(comodel_name="qc.test", string="Test", readonly=True)
inspection_lines = fields.One2many(
comodel_name='qc.inspection.line', inverse_name='inspection_id',
string='Inspection lines', readonly=True,
states={'ready': [('readonly', False)]})
internal_notes = fields.Text(string='Internal notes')
comodel_name="qc.inspection.line",
inverse_name="inspection_id",
string="Inspection lines",
readonly=True,
states={"ready": [("readonly", False)]},
)
internal_notes = fields.Text(string="Internal notes")
external_notes = fields.Text(
string='External notes',
states={'success': [('readonly', True)],
'failed': [('readonly', True)]})
string="External notes",
states={"success": [("readonly", True)], "failed": [("readonly", True)]},
)
state = fields.Selection(
[('draft', 'Draft'),
('ready', 'Ready'),
('waiting', 'Waiting supervisor approval'),
('success', 'Quality success'),
('failed', 'Quality failed'),
('canceled', 'Canceled')],
string='State', readonly=True, default='draft',
track_visibility='onchange')
[
("draft", "Draft"),
("ready", "Ready"),
("waiting", "Waiting supervisor approval"),
("success", "Quality success"),
("failed", "Quality failed"),
("canceled", "Canceled"),
],
string="State",
readonly=True,
default="draft",
track_visibility="onchange",
)
success = fields.Boolean(
compute="_compute_success", string='Success',
help='This field will be marked if all tests have succeeded.',
store=True)
compute="_compute_success",
string="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.')
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['res.company']._company_default_get(
'qc.inspection'))
comodel_name="res.company",
string="Company",
readonly=True,
states={"draft": [("readonly", False)]},
default=lambda self: self.env["res.company"]._company_default_get(
"qc.inspection"
),
)
user = fields.Many2one(
comodel_name='res.users', string='Responsible',
track_visibility='always', default=lambda self: self.env.user)
comodel_name="res.users",
string="Responsible",
track_visibility="always",
default=lambda self: self.env.user,
)
@api.model_create_multi
def create(self, val_list):
for vals in val_list:
if vals.get('name', '/') == '/':
vals['name'] = self.env['ir.sequence'] \
.next_by_code('qc.inspection')
if vals.get("name", "/") == "/":
vals["name"] = self.env["ir.sequence"].next_by_code("qc.inspection")
return super(QcInspection, self).create(vals)
@api.multi
@@ -103,68 +136,74 @@ class QcInspection(models.Model):
for inspection in self:
if inspection.auto_generated:
raise exceptions.UserError(
_("You cannot remove an auto-generated inspection."))
if inspection.state != 'draft':
_("You cannot remove an auto-generated inspection.")
)
if inspection.state != "draft":
raise exceptions.UserError(
_("You cannot remove an inspection that is not in draft "
"state."))
_("You cannot remove an inspection that is not in draft " "state.")
)
return super(QcInspection, self).unlink()
@api.multi
def action_draft(self):
self.write({'state': 'draft'})
self.write({"state": "draft"})
@api.multi
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'})
raise exceptions.UserError(_("You must first set the test to perform."))
self.write({"state": "ready"})
@api.multi
def action_confirm(self):
for inspection in self:
for line in inspection.inspection_lines:
if line.question_type == 'qualitative':
if line.question_type == "qualitative":
if not line.qualitative_value:
raise exceptions.UserError(
_("You should provide an answer for all "
"qualitative questions."))
_(
"You should provide an answer for all "
"qualitative questions."
)
)
else:
if not line.uom_id:
raise exceptions.UserError(
_("You should provide a unit of measure for "
"quantitative questions."))
_(
"You should provide a unit of measure for "
"quantitative questions."
)
)
if inspection.success:
inspection.state = 'success'
inspection.state = "success"
else:
inspection.state = 'waiting'
inspection.state = "waiting"
@api.multi
def action_approve(self):
for inspection in self:
if inspection.success:
inspection.state = 'success'
inspection.state = "success"
else:
inspection.state = 'failed'
inspection.state = "failed"
@api.multi
def action_cancel(self):
self.write({'state': 'canceled'})
self.write({"state": "canceled"})
@api.multi
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
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)
trigger_line.test, force_fill=force_fill
)
@api.multi
def _make_inspection(self, object_ref, trigger_line):
@@ -173,8 +212,9 @@ class QcInspection(models.Model):
:param trigger_line: Trigger line instance
:return: Inspection object
"""
inspection = self.create(self._prepare_inspection_header(
object_ref, trigger_line))
inspection = self.create(
self._prepare_inspection_header(object_ref, trigger_line)
)
inspection.set_test(trigger_line)
return inspection
@@ -186,12 +226,13 @@ class QcInspection(models.Model):
:return: List of values for creating the inspection
"""
return {
'object_id': object_ref and '%s,%s' % (object_ref._name,
object_ref.id) or False,
'state': 'ready',
'test': trigger_line.test.id,
'user': trigger_line.user.id,
'auto_generated': True,
"object_id": object_ref
and "{},{}".format(object_ref._name, object_ref.id)
or False,
"state": "ready",
"test": trigger_line.test.id,
"user": trigger_line.user.id,
"auto_generated": True,
}
@api.multi
@@ -199,113 +240,144 @@ class QcInspection(models.Model):
new_data = []
for line in test.test_lines:
data = self._prepare_inspection_line(
test, line, fill=test.fill_correct_values or force_fill)
test, line, fill=test.fill_correct_values or force_fill
)
new_data.append((0, 0, data))
return new_data
@api.multi
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]
"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':
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
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
data["quantitative_value"] = (line.min_value + line.max_value) * 0.5
return data
class QcInspectionLine(models.Model):
_name = 'qc.inspection.line'
_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')
@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 l in self:
if l.question_type == 'qualitative':
if l.question_type == "qualitative":
l.success = l.qualitative_value.ok
else:
if l.uom_id.id == l.test_uom_id.id:
amount = l.quantitative_value
else:
amount = self.env['uom.uom']._compute_quantity(
l.quantitative_value,
l.test_uom_id.id)
amount = self.env["uom.uom"]._compute_quantity(
l.quantitative_value, l.test_uom_id.id
)
l.success = l.max_value >= amount >= l.min_value
@api.depends('possible_ql_values', 'min_value', 'max_value', 'test_uom_id',
'question_type')
@api.depends(
"possible_ql_values", "min_value", "max_value", "test_uom_id", "question_type"
)
def _compute_valid_values(self):
for l in self:
if l.question_type == 'qualitative':
l.valid_values = \
", ".join([x.name for x in l.possible_ql_values if x.ok])
if l.question_type == "qualitative":
l.valid_values = ", ".join(
[x.name for x in l.possible_ql_values if x.ok]
)
else:
l.valid_values = "%s ~ %s" % (
l.valid_values = "{} ~ {}".format(
formatLang(self.env, l.min_value),
formatLang(self.env, l.max_value))
if self.env.ref("uom.group_uom") \
in self.env.user.groups_id:
formatLang(self.env, l.max_value),
)
if self.env.ref("uom.group_uom") in self.env.user.groups_id:
l.valid_values += " %s" % l.test_uom_id.name
inspection_id = fields.Many2one(
comodel_name='qc.inspection', string='Inspection', ondelete='cascade')
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, oldname='product')
comodel_name="product.product",
related="inspection_id.product_id",
store=True,
oldname="product",
)
test_line = fields.Many2one(
comodel_name='qc.test.question', string='Test question',
readonly=True)
comodel_name="qc.test.question", string="Test question", readonly=True
)
possible_ql_values = fields.Many2many(
comodel_name='qc.test.question.value', string='Answers')
comodel_name="qc.test.question.value", string="Answers"
)
quantitative_value = fields.Float(
'Quantitative value', digits=dp.get_precision('Quality Control'),
help="Value of the result for a quantitative question.")
"Quantitative value",
digits=dp.get_precision("Quality Control"),
help="Value of the result for a quantitative question.",
)
qualitative_value = fields.Many2one(
comodel_name='qc.test.question.value', string='Qualitative value',
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(string='Notes')
domain="[('id', 'in', possible_ql_values)]",
)
notes = fields.Text(string="Notes")
min_value = fields.Float(
string='Min', digits=dp.get_precision('Quality Control'),
readonly=True, help="Minimum valid value for a quantitative question.")
string="Min",
digits=dp.get_precision("Quality Control"),
readonly=True,
help="Minimum valid value for a quantitative question.",
)
max_value = fields.Float(
string='Max', digits=dp.get_precision('Quality Control'),
readonly=True, help="Maximum valid value for a quantitative question.")
string="Max",
digits=dp.get_precision("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.")
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)
comodel_name="uom.category", related="test_uom_id.category_id", store=True
)
uom_id = fields.Many2one(
comodel_name='uom.uom', string='UoM',
comodel_name="uom.uom",
string="UoM",
domain="[('category_id', '=', test_uom_category)]",
help="UoM of the inspection value for a quantitative question.")
help="UoM of the inspection value for a quantitative question.",
)
question_type = fields.Selection(
[('qualitative', 'Qualitative'),
('quantitative', 'Quantitative')],
string='Question type', readonly=True)
valid_values = fields.Char(string="Valid values", store=True,
compute="_compute_valid_values")
[("qualitative", "Qualitative"), ("quantitative", "Quantitative")],
string="Question type",
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)
compute="_compute_quality_test_check", string="Success?", store=True
)

View File

@@ -5,7 +5,8 @@
# 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, _
from odoo import _, api, exceptions, fields, models
import odoo.addons.decimal_precision as dp
@@ -13,92 +14,107 @@ 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'
_name = "qc.test"
_description = "Quality control test"
@api.multi
def object_selection_values(self):
return set()
@api.onchange('type')
@api.onchange("type")
def onchange_type(self):
if self.type == 'generic':
if self.type == "generic":
self.object_id = False
active = fields.Boolean('Active', default=True)
name = fields.Char(
string='Name', required=True, translate=True)
active = fields.Boolean("Active", default=True)
name = fields.Char(string="Name", required=True, translate=True)
test_lines = fields.One2many(
comodel_name='qc.test.question', inverse_name='test',
string='Questions', copy=True)
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')
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')],
string='Type', required=True, default='generic')
category = fields.Many2one(
comodel_name='qc.test.category', string='Category')
[("generic", "Generic"), ("related", "Related")],
string="Type",
required=True,
default="generic",
)
category = fields.Many2one(comodel_name="qc.test.category", string="Category")
company_id = fields.Many2one(
comodel_name='res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get(
'qc.test'))
comodel_name="res.company",
string="Company",
default=lambda self: self.env["res.company"]._company_default_get("qc.test"),
)
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')
_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')):
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])
_(
"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')
@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:
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])
_(
"Question '%s' is not valid: "
"minimum value can't be higher than maximum value."
)
% tc.name_get()[0][1]
)
sequence = fields.Integer(
string='Sequence', required=True, default="10")
test = fields.Many2one(comodel_name='qc.test', string='Test')
name = fields.Char(
string='Name', required=True, translate=True)
sequence = fields.Integer(string="Sequence", required=True, default="10")
test = fields.Many2one(comodel_name="qc.test", string="Test")
name = fields.Char(string="Name", required=True, translate=True)
type = fields.Selection(
[('qualitative', 'Qualitative'),
('quantitative', 'Quantitative')], string='Type', required=True)
[("qualitative", "Qualitative"), ("quantitative", "Quantitative")],
string="Type",
required=True,
)
ql_values = fields.One2many(
comodel_name='qc.test.question.value', inverse_name="test_line",
string='Qualitative values', copy=True)
notes = fields.Text(string='Notes')
min_value = fields.Float(string='Min',
digits=dp.get_precision('Quality Control'))
max_value = fields.Float(string='Max',
digits=dp.get_precision('Quality Control'),)
uom_id = fields.Many2one(comodel_name='uom.uom', string='Uom')
comodel_name="qc.test.question.value",
inverse_name="test_line",
string="Qualitative values",
copy=True,
)
notes = fields.Text(string="Notes")
min_value = fields.Float(string="Min", digits=dp.get_precision("Quality Control"))
max_value = fields.Float(string="Max", digits=dp.get_precision("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.'
_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(
string='Name', required=True, translate=True)
test_line = fields.Many2one(comodel_name="qc.test.question", string="Test question")
name = fields.Char(string="Name", required=True, translate=True)
ok = fields.Boolean(
string='Correct answer?',
help="When this field is marked, the answer is considered correct.")
string="Correct answer?",
help="When this field is marked, the answer is considered correct.",
)

View File

@@ -5,45 +5,51 @@
# 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, _
from odoo import _, api, exceptions, fields, models
class QcTestTemplateCategory(models.Model):
_name = 'qc.test.category'
_description = 'Test category'
_name = "qc.test.category"
_description = "Test category"
@api.multi
@api.depends('name', 'parent_id')
@api.depends("name", "parent_id")
def _compute_get_complete_name(self):
for record in self:
names = [record.name or '']
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')
@api.constrains("parent_id")
def _check_recursion(self):
ids = self.ids
level = 100
while ids:
parents = self.search([('id', 'in', ids),
('parent_id', '!=', False)])
ids = list(set([x.parent_id.id for x in parents]))
parents = self.search([("id", "in", ids), ("parent_id", "!=", False)])
ids = list({x.parent_id.id for x in parents})
if not level:
raise exceptions.UserError(
_('Error! You can not create recursive categories.'))
_("Error! You can not create recursive categories.")
)
level -= 1
name = fields.Char('Name', required=True, translate=True)
name = fields.Char("Name", required=True, translate=True)
parent_id = fields.Many2one(
comodel_name='qc.test.category', string='Parent category')
comodel_name="qc.test.category", string="Parent category"
)
complete_name = fields.Char(
compute="_compute_get_complete_name", string='Full name')
compute="_compute_get_complete_name", string="Full name"
)
child_ids = fields.One2many(
comodel_name='qc.test.category', inverse_name='parent_id',
string='Child categories')
comodel_name="qc.test.category",
inverse_name="parent_id",
string="Child categories",
)
active = fields.Boolean(
string='Active', default=True,
help="This field allows you to hide the category without removing it.")
string="Active",
default=True,
help="This field allows you to hide the category without removing it.",
)

View File

@@ -9,17 +9,19 @@ from odoo import fields, models
class QcTrigger(models.Model):
_name = 'qc.trigger'
_description = 'Quality control trigger'
_name = "qc.trigger"
_description = "Quality control trigger"
name = fields.Char(string='Name', required=True,
translate=True)
active = fields.Boolean(string='Active', default=True)
name = fields.Char(string="Name", required=True, translate=True)
active = fields.Boolean(string="Active", default=True)
company_id = fields.Many2one(
comodel_name='res.company', string='Company',
default=lambda self: self.env['res.company']._company_default_get(
'qc.test'))
comodel_name="res.company",
string="Company",
default=lambda self: self.env["res.company"]._company_default_get("qc.test"),
)
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')
string="Selectable by partner",
default=False,
readonly=True,
help="This technical field is to allow to filter by partner in" " triggers",
)

View File

@@ -25,13 +25,19 @@ class QcTriggerLine(models.AbstractModel):
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',
track_visibility='always', default=lambda self: self.env.user)
comodel_name="res.users",
string="Responsible",
track_visibility="always",
default=lambda self: self.env.user,
)
partners = fields.Many2many(
comodel_name='res.partner', string='Partners',
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)]")
comodel_name="res.partner",
string="Partners",
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)]",
)
def get_trigger_line_for_product(self, trigger, product, partner=False):
"""Overridable method for getting trigger_line associated to a product.
@@ -53,15 +59,18 @@ class QcTriggerProductCategoryLine(models.Model):
def get_trigger_line_for_product(self, trigger, product, partner=False):
trigger_lines = super(
QcTriggerProductCategoryLine,
self).get_trigger_line_for_product(trigger, product,
partner=partner)
QcTriggerProductCategoryLine, self
).get_trigger_line_for_product(trigger, product, partner=partner)
category = product.categ_id
while category:
for trigger_line in category.qc_triggers.filtered(
lambda r: r.trigger == trigger and (
not r.partners or not partner or
partner.commercial_partner_id in r.partners)):
lambda r: r.trigger == trigger
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
@@ -75,14 +84,17 @@ class QcTriggerProductTemplateLine(models.Model):
def get_trigger_line_for_product(self, trigger, product, partner=False):
trigger_lines = super(
QcTriggerProductTemplateLine,
self).get_trigger_line_for_product(trigger, product,
partner=partner)
QcTriggerProductTemplateLine, self
).get_trigger_line_for_product(trigger, product, partner=partner)
for trigger_line in product.product_tmpl_id.qc_triggers.filtered(
lambda r: r.trigger == trigger and (
not r.partners or not partner or
partner.commercial_partner_id in r.partners) and
r.test.active):
lambda r: r.trigger == trigger
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
@@ -94,14 +106,17 @@ class QcTriggerProductLine(models.Model):
product = fields.Many2one(comodel_name="product.product")
def get_trigger_line_for_product(self, trigger, product, partner=False):
trigger_lines = super(
QcTriggerProductLine,
self).get_trigger_line_for_product(trigger, product,
partner=partner)
trigger_lines = super(QcTriggerProductLine, self).get_trigger_line_for_product(
trigger, product, partner=partner
)
for trigger_line in product.qc_triggers.filtered(
lambda r: r.trigger == trigger and (
not r.partners or not partner or
partner.commercial_partner_id in r.partners) and
r.test.active):
lambda r: r.trigger == trigger
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

View File

@@ -26,4 +26,3 @@ The complete inspection workflow is:
| -> Failure (Pending approval) -> Approved
Based on the nan_quality_control_* modules from NaN·tic.

View File

@@ -1,3 +1,3 @@
This module provides a generic infrastructure for quality tests. The idea is
that it can be later reused for doing quality inspections on production lots
or any other area of the company.
or any other area of the company.

View File

@@ -1 +1 @@
* Make translatable the trigger name.
* Make translatable the trigger name.

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,42 +6,44 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.module.category" id="module_category_quality_control">
<field name="name">Quality control</field>
</record>
<record id="group_quality_control_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="module_category_quality_control"/>
<field name="category_id" ref="module_category_quality_control" />
</record>
<record id="group_quality_control_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="module_category_quality_control"/>
<field name="implied_ids" eval="[(4, ref('group_quality_control_user'))]"/>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
<field name="category_id" ref="module_category_quality_control" />
<field name="implied_ids" eval="[(4, ref('group_quality_control_user'))]" />
<field
name="users"
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
/>
</record>
<record id="qc_test_multi_company_rule" model="ir.rule">
<field name="name">Quality control test multi-company</field>
<field name="model_id" ref="model_qc_test"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
<field name="model_id" ref="model_qc_test" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
<record id="qc_inspection_multi_company_rule" model="ir.rule">
<field name="name">Quality control inspection multi-company</field>
<field name="model_id" ref="model_qc_inspection"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
<field name="model_id" ref="model_qc_inspection" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
<record id="qc_trigger_multi_company_rule" model="ir.rule">
<field name="name">Quality control trigger multi-company</field>
<field name="model_id" ref="model_qc_trigger"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
<field name="model_id" ref="model_qc_trigger" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</odoo>

View File

@@ -5,204 +5,220 @@
# Copyright 2017 Simone Rubino - Agile Business Group
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo import exceptions
from ..models.qc_trigger_line import\
_filter_trigger_lines
from odoo.tests.common import TransactionCase
from ..models.qc_trigger_line import _filter_trigger_lines
class TestQualityControl(TransactionCase):
def setUp(self):
super(TestQualityControl, self).setUp()
self.inspection_model = self.env['qc.inspection']
self.category_model = self.env['qc.test.category']
self.question_model = self.env['qc.test.question']
self.wizard_model = self.env['qc.inspection.set.test']
self.qc_trigger = self.env['qc.trigger'].create({
'name': 'Test Trigger',
'active': True,
})
self.test = self.env.ref('quality_control.qc_test_1')
self.val_ok = self.env.ref('quality_control.qc_test_question_value_1')
self.val_ko = self.env.ref('quality_control.qc_test_question_value_2')
self.qn_question = self.env.ref('quality_control.qc_test_question_2')
self.inspection_model = self.env["qc.inspection"]
self.category_model = self.env["qc.test.category"]
self.question_model = self.env["qc.test.question"]
self.wizard_model = self.env["qc.inspection.set.test"]
self.qc_trigger = self.env["qc.trigger"].create(
{"name": "Test Trigger", "active": True}
)
self.test = self.env.ref("quality_control.qc_test_1")
self.val_ok = self.env.ref("quality_control.qc_test_question_value_1")
self.val_ko = self.env.ref("quality_control.qc_test_question_value_2")
self.qn_question = self.env.ref("quality_control.qc_test_question_2")
self.cat_generic = self.env.ref(
'quality_control.qc_test_template_category_generic')
self.product = self.env.ref('product.product_product_11')
inspection_lines = (
self.inspection_model._prepare_inspection_lines(self.test))
self.inspection1 = self.inspection_model.create({
'name': 'Test Inspection',
'inspection_lines': inspection_lines,
})
"quality_control.qc_test_template_category_generic"
)
self.product = self.env.ref("product.product_product_11")
inspection_lines = self.inspection_model._prepare_inspection_lines(self.test)
self.inspection1 = self.inspection_model.create(
{"name": "Test Inspection", "inspection_lines": inspection_lines}
)
self.wizard = self.wizard_model.with_context(
active_id=self.inspection1.id).create({
'test': self.test.id,
})
active_id=self.inspection1.id
).create({"test": self.test.id})
self.wizard.action_create_test()
self.inspection1.action_todo()
def test_inspection_correct(self):
for line in self.inspection1.inspection_lines:
if line.question_type == 'qualitative':
if line.question_type == "qualitative":
line.qualitative_value = self.val_ok
if line.question_type == 'quantitative':
if line.question_type == "quantitative":
line.quantitative_value = 5.0
self.inspection1.action_confirm()
for line in self.inspection1.inspection_lines:
self.assertTrue(
line.success,
'Incorrect state in inspection line %s' % line.name)
line.success, "Incorrect state in inspection line %s" % line.name
)
self.assertTrue(
self.inspection1.success,
'Incorrect state in inspection %s' % self.inspection1.name)
self.assertEqual(self.inspection1.state, 'success')
"Incorrect state in inspection %s" % self.inspection1.name,
)
self.assertEqual(self.inspection1.state, "success")
self.inspection1.action_approve()
self.assertEqual(self.inspection1.state, 'success')
self.assertEqual(self.inspection1.state, "success")
def test_inspection_incorrect(self):
for line in self.inspection1.inspection_lines:
if line.question_type == 'qualitative':
if line.question_type == "qualitative":
line.qualitative_value = self.val_ko
if line.question_type == 'quantitative':
if line.question_type == "quantitative":
line.quantitative_value = 15.0
self.inspection1.action_confirm()
for line in self.inspection1.inspection_lines:
self.assertFalse(
line.success,
'Incorrect state in inspection line %s' % line.name)
line.success, "Incorrect state in inspection line %s" % line.name
)
self.assertFalse(
self.inspection1.success,
'Incorrect state in inspection %s' % self.inspection1.name)
self.assertEqual(self.inspection1.state, 'waiting')
"Incorrect state in inspection %s" % self.inspection1.name,
)
self.assertEqual(self.inspection1.state, "waiting")
self.inspection1.action_approve()
self.assertEqual(self.inspection1.state, 'failed')
self.assertEqual(self.inspection1.state, "failed")
def test_actions_errors(self):
inspection2 = self.inspection1.copy()
inspection2.action_draft()
inspection2.write({'test': False})
inspection2.write({"test": False})
with self.assertRaises(exceptions.UserError):
inspection2.action_todo()
inspection3 = self.inspection1.copy()
inspection3.write({
'inspection_lines':
self.inspection_model._prepare_inspection_lines(inspection3.test)
})
inspection3.write(
{
"inspection_lines": self.inspection_model._prepare_inspection_lines(
inspection3.test
)
}
)
for line in inspection3.inspection_lines:
if line.question_type == 'quantitative':
if line.question_type == "quantitative":
line.quantitative_value = 15.0
with self.assertRaises(exceptions.UserError):
inspection3.action_confirm()
inspection4 = self.inspection1.copy()
inspection4.write({
'inspection_lines':
self.inspection_model._prepare_inspection_lines(inspection4.test)
})
inspection4.write(
{
"inspection_lines": self.inspection_model._prepare_inspection_lines(
inspection4.test
)
}
)
for line in inspection4.inspection_lines:
if line.question_type == 'quantitative':
line.write({
'uom_id': False,
'quantitative_value': 15.0,
})
elif line.question_type == 'qualitative':
if line.question_type == "quantitative":
line.write({"uom_id": False, "quantitative_value": 15.0})
elif line.question_type == "qualitative":
line.qualitative_value = self.val_ok
with self.assertRaises(exceptions.UserError):
inspection4.action_confirm()
def test_categories(self):
category1 = self.category_model.create({
'name': 'Category ONE',
})
category2 = self.category_model.create({
'name': 'Category TWO',
'parent_id': category1.id,
})
category1 = self.category_model.create({"name": "Category ONE"})
category2 = self.category_model.create(
{"name": "Category TWO", "parent_id": category1.id}
)
self.assertEqual(
category2.complete_name,
'%s / %s' % (category1.name, category2.name),
'Something went wrong when computing complete name')
"{} / {}".format(category1.name, category2.name),
"Something went wrong when computing complete name",
)
with self.assertRaises(exceptions.ValidationError):
category1.parent_id = category2.id
def test_get_qc_trigger_product(self):
self.test.write({
'fill_correct_values': True,
})
self.test.write({"fill_correct_values": True})
trigger_lines = set()
self.product.write({
'qc_triggers': [(0, 0, {'trigger': self.qc_trigger.id,
'test': self.test.id})],
})
self.product.product_tmpl_id.write({
'qc_triggers': [(0, 0, {'trigger': self.qc_trigger.id,
'test': self.test.id})],
})
self.product.categ_id.write({
'qc_triggers': [(0, 0, {'trigger': self.qc_trigger.id,
'test': self.test.id})],
})
for model in ['qc.trigger.product_category_line',
'qc.trigger.product_template_line',
'qc.trigger.product_line']:
self.product.write(
{
"qc_triggers": [
(0, 0, {"trigger": self.qc_trigger.id, "test": self.test.id})
],
}
)
self.product.product_tmpl_id.write(
{
"qc_triggers": [
(0, 0, {"trigger": self.qc_trigger.id, "test": self.test.id})
],
}
)
self.product.categ_id.write(
{
"qc_triggers": [
(0, 0, {"trigger": self.qc_trigger.id, "test": self.test.id})
],
}
)
for model in [
"qc.trigger.product_category_line",
"qc.trigger.product_template_line",
"qc.trigger.product_line",
]:
trigger_lines = trigger_lines.union(
self.env[model].get_trigger_line_for_product(
self.qc_trigger, self.product))
self.qc_trigger, self.product
)
)
self.assertEqual(len(trigger_lines), 3)
filtered_trigger_lines = _filter_trigger_lines(trigger_lines)
self.assertEqual(len(filtered_trigger_lines), 1)
for trigger_line in filtered_trigger_lines:
inspection = self.inspection_model._make_inspection(
self.product, trigger_line)
self.assertEqual(inspection.state, 'ready')
self.product, trigger_line
)
self.assertEqual(inspection.state, "ready")
self.assertTrue(inspection.auto_generated)
self.assertEqual(inspection.test, self.test)
for line in inspection.inspection_lines:
if line.question_type == 'qualitative':
if line.question_type == "qualitative":
self.assertEqual(line.qualitative_value, self.val_ok)
elif line.question_type == 'quantitative':
elif line.question_type == "quantitative":
self.assertAlmostEqual(
round(line.quantitative_value, 2), round((
self.qn_question.min_value +
self.qn_question.max_value) * 0.5, 2))
round(line.quantitative_value, 2),
round(
(self.qn_question.min_value + self.qn_question.max_value)
* 0.5,
2,
),
)
def test_qc_inspection_not_draft_unlink(self):
with self.assertRaises(exceptions.UserError):
self.inspection1.unlink()
inspection2 = self.inspection1.copy()
inspection2.action_cancel()
self.assertEqual(inspection2.state, 'canceled')
self.assertEqual(inspection2.state, "canceled")
inspection2.action_draft()
self.assertEqual(inspection2.state, 'draft')
self.assertEqual(inspection2.state, "draft")
inspection2.unlink()
def test_qc_inspection_auto_generate_unlink(self):
inspection2 = self.inspection1.copy()
inspection2.write({
'auto_generated': True,
})
inspection2.write({"auto_generated": True})
with self.assertRaises(exceptions.UserError):
inspection2.unlink()
def test_qc_inspection_product(self):
self.inspection1.write({
'object_id': '%s,%d' % (self.product._name, self.product.id),
})
self.inspection1.write(
{"object_id": "%s,%d" % (self.product._name, self.product.id)}
)
self.assertEqual(self.inspection1.product_id, self.product)
def test_qc_test_question_constraints(self):
with self.assertRaises(exceptions.ValidationError):
self.question_model.create({
'name': 'Quantitative Question',
'type': 'quantitative',
'min_value': 1.0,
'max_value': 0.0,
})
self.question_model.create(
{
"name": "Quantitative Question",
"type": "quantitative",
"min_value": 1.0,
"max_value": 0.0,
}
)
with self.assertRaises(exceptions.ValidationError):
self.question_model.create({
'name': 'Qualitative Question',
'type': 'qualitative',
'ql_values': [(0, 0, {'name': 'Qualitative answer',
'ok': False})],
})
self.question_model.create(
{
"name": "Qualitative Question",
"type": "qualitative",
"ql_values": [(0, 0, {"name": "Qualitative answer", "ok": False})],
}
)

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,17 +6,19 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="product_category_qc_form_view">
<field name="name">product.category.qc</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="product.product_category_form_view"/>
<field name="inherit_id" ref="product.product_category_form_view" />
<field name="arch" type="xml">
<group name="first" position="after">
<group name="qc" string="Quality control">
<field name="qc_triggers" nolabel="1">
<tree string="Quality control triggers" editable="bottom">
<field name="trigger" options="{'no_create': True, 'no_edit': True, 'no_open': True}" />
<field
name="trigger"
options="{'no_create': True, 'no_edit': True, 'no_open': True}"
/>
<field name="test" />
<field name="user" />
<field name="partners" widget="many2many_tags" />
@@ -26,5 +28,4 @@
</group>
</field>
</record>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,19 +6,24 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="product_template_qc_form_view">
<field name="name">product.template.qc</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="groups_id" eval="[(4, ref('quality_control.group_quality_control_user'))]" />
<field name="inherit_id" ref="product.product_template_only_form_view" />
<field
name="groups_id"
eval="[(4, ref('quality_control.group_quality_control_user'))]"
/>
<field name="arch" type="xml">
<page name="inventory" position="inside">
<group name="qc" string="Quality control">
<field name="qc_triggers" nolabel="1">
<tree string="Quality control triggers" editable="bottom">
<field name="trigger" options="{'no_create': True, 'no_edit': True, 'no_open': True}"/>
<field name="test"/>
<field
name="trigger"
options="{'no_create': True, 'no_edit': True, 'no_open': True}"
/>
<field name="test" />
<field name="user" />
<field name="partners" widget="many2many_tags" />
</tree>
@@ -27,5 +32,4 @@
</page>
</field>
</record>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,56 +6,69 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="qc_inspection_form_view">
<field name="name">qc.inspection.form</field>
<field name="model">qc.inspection</field>
<field name="arch" type="xml">
<form string="Inspection">
<header>
<button name="action_draft"
type="object"
attrs="{'invisible': [('state', '!=', 'canceled')]}"
string="Draft" />
<button name="action_todo"
type="object"
class="oe_highlight"
states="draft"
string="Mark todo" />
<button name="action_confirm"
type="object"
class="oe_highlight"
states="ready"
string="Confirm"
icon="fa-check" />
<button name="action_approve"
type="object"
states="waiting"
class="oe_highlight"
groups="quality_control.group_quality_control_manager"
string="Approve" />
<button name="action_cancel"
type="object"
attrs="{'invisible': [('state', 'not in', ['waiting', 'ready', 'failed', 'success'])]}"
string="Cancel"
icon="fa-ban" />
<field name="state"
widget="statusbar"
statusbar_visible="draft,waiting,success"
statusbar_colors='{"success": "blue", "failed": "red"}' />
<button
name="action_draft"
type="object"
attrs="{'invisible': [('state', '!=', 'canceled')]}"
string="Draft"
/>
<button
name="action_todo"
type="object"
class="oe_highlight"
states="draft"
string="Mark todo"
/>
<button
name="action_confirm"
type="object"
class="oe_highlight"
states="ready"
string="Confirm"
icon="fa-check"
/>
<button
name="action_approve"
type="object"
states="waiting"
class="oe_highlight"
groups="quality_control.group_quality_control_manager"
string="Approve"
/>
<button
name="action_cancel"
type="object"
attrs="{'invisible': [('state', 'not in', ['waiting', 'ready', 'failed', 'success'])]}"
string="Cancel"
icon="fa-ban"
/>
<field
name="state"
widget="statusbar"
statusbar_visible="draft,waiting,success"
statusbar_colors='{"success": "blue", "failed": "red"}'
/>
</header>
<sheet>
<div class="oe_right oe_button_box" name="buttons">
<button class="oe_inline oe_stat_button"
type="action"
name="%(action_qc_inspection_set_test)d"
icon="fa-bookmark-o"
states="draft"
string="Set test" />
<button
class="oe_inline oe_stat_button"
type="action"
name="%(action_qc_inspection_set_test)d"
icon="fa-bookmark-o"
states="draft"
string="Set test"
/>
</div>
<h1>
<label string="Inspection " for="name"/>
<field name="name" class="oe_inline"/>
<label string="Inspection " for="name" />
<field name="name" class="oe_inline" />
</h1>
<group>
<group>
@@ -74,45 +87,57 @@
<notebook>
<page string="Questions">
<field name="inspection_lines" nolabel="1">
<tree string="Inspection lines" editable="top" delete="false" create="false">
<tree
string="Inspection lines"
editable="top"
delete="false"
create="false"
>
<field name="name" />
<field name="question_type" />
<field name="possible_ql_values" invisible="1" />
<field name="qualitative_value"
attrs="{'readonly': [('question_type', '=', 'quantitative')]}" />
<field name="quantitative_value"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}" />
<field name="uom_id"
groups="uom.group_uom"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}" />
<field name="test_uom_category" invisible="1"/>
<field name="min_value" invisible="1"/>
<field name="max_value" invisible="1"/>
<field
name="qualitative_value"
attrs="{'readonly': [('question_type', '=', 'quantitative')]}"
/>
<field
name="quantitative_value"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}"
/>
<field
name="uom_id"
groups="uom.group_uom"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}"
/>
<field name="test_uom_category" invisible="1" />
<field name="min_value" invisible="1" />
<field name="max_value" invisible="1" />
<field name="valid_values" />
<field name="success" />
</tree>
</field>
</page>
<page string="Notes">
<group string="Internal notes" >
<field name="internal_notes"
nolabel="1" />
<group string="Internal notes">
<field name="internal_notes" nolabel="1" />
</group>
<group string="External notes" >
<field name="external_notes"
nolabel="1" />
<group string="External notes">
<field name="external_notes" nolabel="1" />
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="message_ids" widget="mail_thread"/>
<field
name="message_follower_ids"
widget="mail_followers"
groups="base.group_user"
/>
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<record model="ir.ui.view" id="qc_inspection_tree_view">
<field name="name">qc.inspection.tree</field>
<field name="model">qc.inspection</field>
@@ -128,7 +153,6 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="qc_inspection_search_view">
<field name="name">qc.inspection.search</field>
<field name="model">qc.inspection</field>
@@ -142,83 +166,110 @@
<field name="test" />
</group>
<newline />
<filter string="Correct"
name="correct"
domain="[('success', '=', True)]"/>
<filter string="Incorrect"
name="incorrect"
domain="[('success', '=', False)]"/>
<filter
string="Correct"
name="correct"
domain="[('success', '=', True)]"
/>
<filter
string="Incorrect"
name="incorrect"
domain="[('success', '=', False)]"
/>
<newline />
<group expand="0" string="Group by...">
<filter string="Reference"
name="group_by_object_id"
domain="[]"
context="{'group_by': 'object_id'}" />
<filter string="Test"
name="group_by_test"
domain="[]"
context="{'group_by': 'test'}" />
<filter string="Responsible"
name="group_by_user"
domain="[]"
context="{'group_by': 'user'}" />
<filter string="Product"
name="group_by_product_id"
domain="[]"
context="{'group_by': 'product_id'}" />
<filter string="State"
name="group_by_state"
domain="[]"
context="{'group_by': 'state'}" />
<filter string="Success"
name="group_by_success"
domain="[]"
context="{'group_by': 'success'}" />
<filter string="Auto-generated"
name="group_by_auto_generated"
domain="[]"
context="{'group_by': 'auto_generated'}" />
<filter
string="Reference"
name="group_by_object_id"
domain="[]"
context="{'group_by': 'object_id'}"
/>
<filter
string="Test"
name="group_by_test"
domain="[]"
context="{'group_by': 'test'}"
/>
<filter
string="Responsible"
name="group_by_user"
domain="[]"
context="{'group_by': 'user'}"
/>
<filter
string="Product"
name="group_by_product_id"
domain="[]"
context="{'group_by': 'product_id'}"
/>
<filter
string="State"
name="group_by_state"
domain="[]"
context="{'group_by': 'state'}"
/>
<filter
string="Success"
name="group_by_success"
domain="[]"
context="{'group_by': 'success'}"
/>
<filter
string="Auto-generated"
name="group_by_auto_generated"
domain="[]"
context="{'group_by': 'auto_generated'}"
/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_qc_inspection">
<field name="name">Inspections</field>
<field name="res_model">qc.inspection</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Inspections"
parent="qc_inspection_menu_parent"
id="qc_inspection_menu"
action="action_qc_inspection" />
<menuitem
name="Inspections"
parent="qc_inspection_menu_parent"
id="qc_inspection_menu"
action="action_qc_inspection"
/>
<record model="ir.ui.view" id="qc_inspection_line_tree_view">
<field name="name">qc.inspection.line.tree</field>
<field name="model">qc.inspection.line</field>
<field name="arch" type="xml">
<tree string="Inspection lines" delete="false" create="false" colors="red: success==False">
<tree
string="Inspection lines"
delete="false"
create="false"
colors="red: success==False"
>
<field name="inspection_id" />
<field name="product_id" />
<field name="name" />
<field name="question_type" />
<field name="possible_ql_values" invisible="1" />
<field name="qualitative_value"
attrs="{'readonly': [('question_type', '=', 'quantitative')]}" />
<field name="quantitative_value"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}" />
<field name="uom_id"
groups="uom.group_uom"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}" />
<field name="test_uom_category" invisible="1"/>
<field
name="qualitative_value"
attrs="{'readonly': [('question_type', '=', 'quantitative')]}"
/>
<field
name="quantitative_value"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}"
/>
<field
name="uom_id"
groups="uom.group_uom"
attrs="{'readonly': [('question_type', '=', 'qualitative')]}"
/>
<field name="test_uom_category" invisible="1" />
<field name="valid_values" />
<field name="success" />
</tree>
</field>
</record>
<record model="ir.ui.view" id="qc_inspection_line_search_view">
<field name="name">qc.inspection.line.search</field>
<field name="model">qc.inspection.line</field>
@@ -231,46 +282,56 @@
<field name="success" />
</group>
<newline />
<filter string="Correct"
name="correct"
domain="[('success', '=', True)]"/>
<filter string="Incorrect"
name="incorrect"
domain="[('success', '=', False)]"/>
<filter
string="Correct"
name="correct"
domain="[('success', '=', True)]"
/>
<filter
string="Incorrect"
name="incorrect"
domain="[('success', '=', False)]"
/>
<newline />
<group expand="0" string="Group by...">
<filter string="Inspection"
name="group_by_inspection_id"
domain="[]"
context="{'group_by': 'inspection_id'}" />
<filter string="Product"
name="group_by_product_id"
domain="[]"
context="{'group_by': 'product_id'}" />
<filter string="Question"
name="group_by_name"
domain="[]"
context="{'group_by': 'name'}" />
<filter string="Success"
name="group_by_success"
domain="[]"
context="{'group_by': 'success'}" />
<filter
string="Inspection"
name="group_by_inspection_id"
domain="[]"
context="{'group_by': 'inspection_id'}"
/>
<filter
string="Product"
name="group_by_product_id"
domain="[]"
context="{'group_by': 'product_id'}"
/>
<filter
string="Question"
name="group_by_name"
domain="[]"
context="{'group_by': 'name'}"
/>
<filter
string="Success"
name="group_by_success"
domain="[]"
context="{'group_by': 'success'}"
/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_qc_inspection_line">
<field name="name">Inspection lines</field>
<field name="res_model">qc.inspection.line</field>
<field name="view_type">form</field>
<field name="view_mode">tree</field>
</record>
<menuitem name="Inspection lines"
parent="qc_inspection_menu_parent"
id="qc_inspection_lines_menu"
action="action_qc_inspection_line" />
<menuitem
name="Inspection lines"
parent="qc_inspection_menu_parent"
id="qc_inspection_lines_menu"
action="action_qc_inspection_line"
/>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,29 +6,31 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<menuitem name="Quality control"
id="qc_menu"
groups="group_quality_control_user"
web_icon="quality_control,static/description/icon.png"
sequence="40"
<menuitem
name="Quality control"
id="qc_menu"
groups="group_quality_control_user"
web_icon="quality_control,static/description/icon.png"
sequence="40"
/>
<menuitem
name="Inspections"
parent="qc_menu"
id="qc_inspection_menu_parent"
sequence="10"
/>
<menuitem
parent="qc_menu"
name="Tests"
id="qc_menu_test_parent"
groups="group_quality_control_manager"
sequence="20"
/>
<menuitem
name="Configuration"
id="menu_qc_config"
groups="base.group_system"
parent="qc_menu"
sequence="100"
/>
<menuitem name="Inspections"
parent="qc_menu"
id="qc_inspection_menu_parent"
sequence="10"/>
<menuitem parent="qc_menu"
name="Tests"
id="qc_menu_test_parent"
groups="group_quality_control_manager"
sequence="20"/>
<menuitem name="Configuration"
id="menu_qc_config"
groups="base.group_system"
parent="qc_menu"
sequence="100"/>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,32 +6,30 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="qc_test_category_tree_view">
<field name="name">qc.test.category.tree</field>
<field name="model">qc.test.category</field>
<field name="arch" type="xml">
<tree string="Test categories" editable="bottom">
<field name="complete_name"/>
<field name="name"/>
<field name="parent_id"/>
<field name="active"/>
<field name="complete_name" />
<field name="name" />
<field name="parent_id" />
<field name="active" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_qc_test_category">
<field name="name">Test categories</field>
<field name="res_model">qc.test.category</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem name="Test categories"
parent="qc_menu_test_parent"
id="qc_test_category_menu"
action="action_qc_test_category"
groups="group_quality_control_manager"
sequence="10" />
<menuitem
name="Test categories"
parent="qc_menu_test_parent"
id="qc_test_category_menu"
action="action_qc_test_category"
groups="group_quality_control_manager"
sequence="10"
/>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,33 +6,37 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="qc_test_form_view">
<field name="name">qc.test.form</field>
<field name="model">qc.test</field>
<field name="arch" type="xml">
<form string="Test">
<sheet>
<label for="name" class="oe_edit_only"/>
<label for="name" class="oe_edit_only" />
<h1>
<field name="name" class="oe_inline"/>
<field name="name" class="oe_inline" />
</h1>
<group>
<group>
<field name="type" />
<field name="object_id"
attrs="{'invisible': [('type','=','generic')]}"/>
<field
name="object_id"
attrs="{'invisible': [('type','=','generic')]}"
/>
<field name="active" />
</group>
<group>
<field name="category" />
<field name="fill_correct_values" />
<field name="company_id" groups="base.group_multi_company"/>
<field
name="company_id"
groups="base.group_multi_company"
/>
</group>
</group>
<field name="test_lines" nolabel="1" >
<field name="test_lines" nolabel="1">
<tree string="Questions">
<field name="sequence" widget="handle"/>
<field name="sequence" widget="handle" />
<field name="name" />
<field name="type" />
<field name="min_value" />
@@ -45,7 +49,6 @@
</form>
</field>
</record>
<record model="ir.ui.view" id="qc_test_tree_view">
<field name="name">qc.test.tree</field>
<field name="model">qc.test</field>
@@ -55,18 +58,16 @@
<field name="category" />
<field name="type" />
<field name="object_id" />
<field name="company_id" groups="base.group_multi_company"/>
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_qc_test">
<field name="name">Tests</field>
<field name="res_model">qc.test</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="qc_test_question_form_view">
<field name="name">qc.test.question.form</field>
<field name="model">qc.test.question</field>
@@ -80,39 +81,51 @@
<field name="sequence" />
<field name="type" />
</group>
<group name="qualitative"
string="Answers"
colspan="4"
attrs="{'invisible': [('type', '!=', 'qualitative')]}">
<field name="ql_values"
nolabel="1"
attrs="{'required': [('type','=','qualitative')]}">
<group
name="qualitative"
string="Answers"
colspan="4"
attrs="{'invisible': [('type', '!=', 'qualitative')]}"
>
<field
name="ql_values"
nolabel="1"
attrs="{'required': [('type','=','qualitative')]}"
>
<tree string="Question value" editable="bottom">
<field name="name" />
<field name="ok" />
</tree>
</field>
</group>
<div name="quantitative"
align="center"
attrs="{'invisible': [('type', '!=', 'quantitative')]}" >
<div
name="quantitative"
align="center"
attrs="{'invisible': [('type', '!=', 'quantitative')]}"
>
<h1 name="quantitative-data">
<span name="quantitative-interval" >
<field name="min_value"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type','=', 'quantitative')]}" />
<span name="quantitative-interval">
<field
name="min_value"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type','=', 'quantitative')]}"
/>
<span> - </span>
<field name="max_value"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type', '=', 'quantitative')]}" />
<field
name="max_value"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type', '=', 'quantitative')]}"
/>
</span>
<span name="quantitative-uom" >
<field name="uom_id"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type', '=', 'quantitative')]}" />
<span name="quantitative-uom">
<field
name="uom_id"
class="oe_inline"
nolabel="1"
attrs="{'required': [('type', '=', 'quantitative')]}"
/>
</span>
</h1>
</div>
@@ -120,12 +133,12 @@
</form>
</field>
</record>
<menuitem name="Tests"
parent="qc_menu_test_parent"
id="qc_test_menu"
action="action_qc_test"
groups="group_quality_control_manager"
sequence="20" />
<menuitem
name="Tests"
parent="qc_menu_test_parent"
id="qc_test_menu"
action="action_qc_test"
groups="group_quality_control_manager"
sequence="20"
/>
</odoo>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,34 +6,30 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.ui.view" id="qc_trigger_form_view">
<field name="name">qc.trigger.form</field>
<field name="model">qc.trigger</field>
<field name="arch" type="xml">
<form string="Quality control trigger">
<group>
<field name="name" />
<field name="active" />
<field name="partner_selectable" />
</group>
<group>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group>
<field name="name" />
<field name="active" />
<field name="partner_selectable" />
</group>
<group>
<field name="company_id" groups="base.group_multi_company" />
</group>
</form>
</field>
</record>
<record model="ir.ui.view" id="qc_trigger_tree_view">
<field name="name">qc.trigger.tree</field>
<field name="model">qc.trigger</field>
<field name="arch" type="xml">
<tree string="Quality control triggers" editable="bottom">
<field name="name" />
<field name="company_id" groups="base.group_multi_company"/>
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
</odoo>

View File

@@ -14,17 +14,16 @@ class QcInspectionSetTest(models.TransientModel):
also fill in all lines of the inspection with the corresponding lines of
the template.
"""
_name = 'qc.inspection.set.test'
_description = 'Set test for inspection'
test = fields.Many2one(comodel_name='qc.test', string='Test')
_name = "qc.inspection.set.test"
_description = "Set test for inspection"
test = fields.Many2one(comodel_name="qc.test", string="Test")
@api.multi
def action_create_test(self):
inspection = self.env['qc.inspection'].browse(
self.env.context['active_id'])
inspection = self.env["qc.inspection"].browse(self.env.context["active_id"])
inspection.test = self.test
inspection.inspection_lines.unlink()
inspection.inspection_lines = inspection._prepare_inspection_lines(
self.test)
inspection.inspection_lines = inspection._prepare_inspection_lines(self.test)
return True

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2010 NaN Projectes de Programari Lliure, S.L.
Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
Copyright 2014 Oihane Crucelaegui - AvanzOSC
@@ -6,7 +6,6 @@
Copyright 2017 Simone Rubino - Agile Business Group
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_qc_test_set_test_form" model="ir.ui.view">
<field name="name">qc.inspection.set.test.form</field>
<field name="model">qc.inspection.set.test</field>
@@ -16,19 +15,18 @@
<field name="test" />
</group>
<footer>
<button name="action_create_test"
string="Accept"
type="object"
class="oe_highlight"/>
<button
name="action_create_test"
string="Accept"
type="object"
class="oe_highlight"
/>
or
<button special="cancel"
class="oe_link"
string="Cancel" />
<button special="cancel" class="oe_link" string="Cancel" />
</footer>
</form>
</field>
</record>
<record id="action_qc_inspection_set_test" model="ir.actions.act_window">
<field name="name">Select test</field>
<field name="type">ir.actions.act_window</field>
@@ -37,5 +35,4 @@
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>