From 508fe0a28b44969b5020bfd865e774037fe8f830 Mon Sep 17 00:00:00 2001 From: lreficent Date: Thu, 25 May 2017 13:30:24 +0200 Subject: [PATCH] [9.0][ADD] quality_control_issue --- quality_control_issue/README.rst | 69 +++++++ quality_control_issue/__init__.py | 5 + quality_control_issue/__openerp__.py | 25 +++ .../data/qc_issue_sequence.xml | 15 ++ quality_control_issue/data/qc_stage_data.xml | 23 +++ quality_control_issue/models/__init__.py | 9 + quality_control_issue/models/qc_issue.py | 173 +++++++++++++++++ .../models/qc_issue_stage.py | 41 ++++ quality_control_issue/models/qc_problem.py | 113 +++++++++++ .../models/qc_problem_group.py | 17 ++ quality_control_issue/models/qc_stage.py | 41 ++++ .../security/ir.model.access.csv | 11 ++ .../quality_control_issue_security.xml | 22 +++ .../static/description/icon.png | Bin 0 -> 7121 bytes .../static/description/icon.svg | 95 ++++++++++ quality_control_issue/views/qc_issue_view.xml | 175 ++++++++++++++++++ .../views/qc_problem_group_view.xml | 48 +++++ .../views/qc_problem_view.xml | 136 ++++++++++++++ .../views/qc_team_dashboard_view.xml | 56 ++++++ 19 files changed, 1074 insertions(+) create mode 100644 quality_control_issue/README.rst create mode 100644 quality_control_issue/__init__.py create mode 100644 quality_control_issue/__openerp__.py create mode 100644 quality_control_issue/data/qc_issue_sequence.xml create mode 100644 quality_control_issue/data/qc_stage_data.xml create mode 100644 quality_control_issue/models/__init__.py create mode 100644 quality_control_issue/models/qc_issue.py create mode 100644 quality_control_issue/models/qc_issue_stage.py create mode 100644 quality_control_issue/models/qc_problem.py create mode 100644 quality_control_issue/models/qc_problem_group.py create mode 100644 quality_control_issue/models/qc_stage.py create mode 100644 quality_control_issue/security/ir.model.access.csv create mode 100644 quality_control_issue/security/quality_control_issue_security.xml create mode 100644 quality_control_issue/static/description/icon.png create mode 100644 quality_control_issue/static/description/icon.svg create mode 100644 quality_control_issue/views/qc_issue_view.xml create mode 100644 quality_control_issue/views/qc_problem_group_view.xml create mode 100644 quality_control_issue/views/qc_problem_view.xml create mode 100644 quality_control_issue/views/qc_team_dashboard_view.xml diff --git a/quality_control_issue/README.rst b/quality_control_issue/README.rst new file mode 100644 index 000000000..f17a29a5a --- /dev/null +++ b/quality_control_issue/README.rst @@ -0,0 +1,69 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +===================== +Quality Control Issue +===================== + +WIP + +This module extends the functionality of quality Control to allow you to +report and manage quality control issues. + +Usage +===== + +To use this module, you need to: + +#. Go to *Quality Control > Issues > QC Issues*. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/129/9.0 + +Known issues / Roadmap +====================== + +Todo: +----- + +* Add Dispositions: RMA, scrap, rework... +* reference to PO, MO, QC... +* Link to Problem tracking... + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smash it by providing detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Lois Rilo + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/quality_control_issue/__init__.py b/quality_control_issue/__init__.py new file mode 100644 index 000000000..7201c0805 --- /dev/null +++ b/quality_control_issue/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/quality_control_issue/__openerp__.py b/quality_control_issue/__openerp__.py new file mode 100644 index 000000000..823c85570 --- /dev/null +++ b/quality_control_issue/__openerp__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Quality Control Issue", + "summary": "Allow to manage and report Quality Control Issues.", + "version": "9.0.1.0.0", + "category": "Quality Control", + "website": "https://odoo-community.org/", + "author": "Eficent , Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["quality_control", "quality_control_team", "stock"], + "data": [ + "security/ir.model.access.csv", + "security/quality_control_issue_security.xml", + "data/qc_issue_sequence.xml", + "data/qc_stage_data.xml", + "views/qc_issue_view.xml", + "views/qc_problem_view.xml", + "views/qc_problem_group_view.xml", + "views/qc_team_dashboard_view.xml", + ], +} diff --git a/quality_control_issue/data/qc_issue_sequence.xml b/quality_control_issue/data/qc_issue_sequence.xml new file mode 100644 index 000000000..d779d8a87 --- /dev/null +++ b/quality_control_issue/data/qc_issue_sequence.xml @@ -0,0 +1,15 @@ + + + + + + + QC Issues + qc.issue + QCI/%(range_year)s/ + 5 + + + + diff --git a/quality_control_issue/data/qc_stage_data.xml b/quality_control_issue/data/qc_stage_data.xml new file mode 100644 index 000000000..25617235c --- /dev/null +++ b/quality_control_issue/data/qc_stage_data.xml @@ -0,0 +1,23 @@ + + + + + + + + New + 1 + False + + + + + + Done + 100 + True + + + + diff --git a/quality_control_issue/models/__init__.py b/quality_control_issue/models/__init__.py new file mode 100644 index 000000000..56785ea53 --- /dev/null +++ b/quality_control_issue/models/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import qc_issue +from . import qc_problem +from . import qc_problem_group +from . import qc_stage +from . import qc_issue_stage diff --git a/quality_control_issue/models/qc_issue.py b/quality_control_issue/models/qc_issue.py new file mode 100644 index 000000000..66df5eafe --- /dev/null +++ b/quality_control_issue/models/qc_issue.py @@ -0,0 +1,173 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models +import openerp.addons.decimal_precision as dp + + +class QualityControlIssue(models.Model): + _name = "qc.issue" + _description = "Quality Control Issue" + _inherit = "mail.thread" + + @api.model + def create(self, vals): + vals['name'] = self.env['ir.sequence'].next_by_code( + 'qc.issue') or '' + return super(QualityControlIssue, self).create(vals) + + @api.one + def _get_uom(self): + self.product_uom = self.product_id.product_tmpl_id.uom_id + + def _get_default_stage_id(self): + """ Gives default stage_id """ + team_id = self.env['qc.team']._get_default_qc_team_id( + user_id=self.env.uid) + return self.issue_stage_find([], team_id, [('fold', '=', False)]) + + @api.multi + def _read_group_stage_ids(self, domain, read_group_order=None, + access_rights_uid=None): + access_rights_uid = access_rights_uid or self._uid + stage_obj = self.env['qc.issue.stage'] + search_domain = [] + qc_team_id = self.env.context.get('default_qc_team_id') or False + if qc_team_id: + search_domain += ['|', ('id', 'in', self.ids)] + search_domain += ['|', ('qc_team_id', '=', qc_team_id)] + search_domain += [('qc_team_id', '=', False)] + else: + search_domain += ['|', ('id', 'in', self.ids)] + search_domain += [('qc_team_id', '=', False)] + # perform search + stage_ids = stage_obj._search(search_domain, + access_rights_uid=access_rights_uid) + result = [stage.name_get()[0] for stage in + stage_obj.browse(stage_ids)] + # restore order of the search + result.sort( + lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + + fold = {} + for stage in stage_obj.browse(stage_ids): + fold[stage.id] = stage.fold or False + return result, fold + + name = fields.Char(readonly=True) + state = fields.Selection( + selection=[("new", "New"), + ("progress", "In Progress"), + ("done", "Done"), + ("cancel", "Cancel")], default="new", + track_visibility='onchange') + product_id = fields.Many2one( + comodel_name="product.product", string="Product", + readonly=True, states={"new": [("readonly", False)]}, + required=True) + product_tracking = fields.Selection(related="product_id.tracking") + product_qty = fields.Float( + string="Product Quantity", required=True, default=1.0, + readonly=True, states={"new": [("readonly", False)]}, + digits_compute=dp.get_precision("Product Unit of Measure")) + product_uom = fields.Many2one( + comodel_name="product.uom", string="Product Unit of Measure", + required=True, default=_get_uom, + readonly=True, states={"new": [("readonly", False)]},) + lot_id = fields.Many2one( + comodel_name="stock.production.lot", string="Lot/Serial Number", + readonly=True, states={"new": [("readonly", False)]},) + location_id = fields.Many2one( + comodel_name="stock.location", string="Location", + readonly=True, states={"new": [("readonly", False)]},) + inspector_id = fields.Many2one( + comodel_name="res.users", string="Inspector", + track_visibility="onchange", + readonly=True, states={"new": [("readonly", False)]}, + default=lambda self: self.env.user, required=True) + responsible_id = fields.Many2one( + comodel_name="res.users", string="Assigned to", + track_visibility="onchange", + states={"done": [("readonly", True)]},) + description = fields.Text( + states={"done": [("readonly", True)]},) + qc_problem_ids = fields.Many2many( + comodel_name="qc.problem", string="Problems", + relation="qc_issue_problem_rel", column1="qc_issue_id", + column2="qc_problem_id", + states={"done": [("readonly", True)]},) + color = fields.Integer(string='Color Index') + stage_id = fields.Many2one( + comodel_name="qc.issue.stage", string='Stage', + track_visibility='onchange', + select=True, default=_get_default_stage_id, + domain="['|', ('qc_team_id', '=', False), " + "('qc_team_id', '=', qc_team_id)]") + qc_team_id = fields.Many2one( + comodel_name='qc.team', string='QC Team', + default=lambda self: self.env[ + 'qc.team'].sudo()._get_default_qc_team_id(user_id=self.env.uid), + index=True, track_visibility='onchange') + company_id = fields.Many2one( + comodel_name='res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + + _group_by_full = { + 'stage_id': _read_group_stage_ids + } + + def issue_stage_find(self, cases, team_id, domain=None, order='sequence'): + """ Override of the base.stage method + Parameter of the stage search taken from the problem: + - team_id: if set, stages must belong to this team or + be a default stage; if not set, stages must be default + stages + """ + team_ids = set() + if team_id: + team_ids.add(team_id) + for problem in cases: + if problem.team_id: + team_ids.add(problem.team_id.id) + search_domain = [] + if team_ids: + search_domain += [('|')] * (len(team_ids) - 1) + for team_id in team_ids: + search_domain.append(('qc_team_id', '=', team_id.id)) + search_domain += list(domain) + # perform search, return the first found + stage_ids = self.env['qc.issue.stage'].search( + search_domain, order=order, limit=1) + if stage_ids: + return stage_ids[0] + return False + + @api.multi + def action_confirm(self): + self.write({'state': 'progress'}) + + @api.multi + def action_done(self): + self.write({'state': 'done'}) + + @api.multi + def action_cancel(self): + self.write({'state': 'cancel'}) + + @api.onchange('product_id') + def _onchange_product_id(self): + self.product_uom = self.product_id.product_tmpl_id.uom_id + if self.lot_id.product_id != self.product_id: + self.lot_id = False + if self.product_id: + return {'domain': { + 'lot_id': [('product_id', '=', self.product_id.id)]}} + return {'domain': {'lot_id': []}} + + @api.onchange("lot_id") + def _onchange_lot_id(self): + product = self.lot_id.product_id + if product: + self.product_id = product + self.product_uom = product.product_tmpl_id.uom_id diff --git a/quality_control_issue/models/qc_issue_stage.py b/quality_control_issue/models/qc_issue_stage.py new file mode 100644 index 000000000..3dfbfbfba --- /dev/null +++ b/quality_control_issue/models/qc_issue_stage.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + +AVAILABLE_PRIORITIES = [ + ('0', 'Normal'), + ('1', 'Low'), + ('2', 'High'), + ('3', 'Very High'), +] + + +class QualityControlIssueStage(models.Model): + _name = "qc.issue.stage" + _rec_name = 'name' + _order = "sequence, name, id" + + @api.model + def default_get(self, fields): + """ Hack : when going from the kanban view, creating a stage with a + qc team in context should not create a stage for the current team only. + """ + ctx = dict(self.env.context) + if ctx.get('default_qc_team_id') and not ctx.get('some_context'): + ctx.pop('default_qc_team_id') + return super(QualityControlIssueStage, + self.with_context(ctx)).default_get(fields) + + name = fields.Char('Stage Name', required=True) + sequence = fields.Integer( + string='Sequence', help="Used to order stages. Lower is better.", + default=1) + qc_team_id = fields.Many2one( + comodel_name='qc.team', string='Quality Control Team', + ondelete='set null') + fold = fields.Boolean( + string='Folded in Pipeline', default=False, + help='This stage is folded in the kanban view when there are no ' + 'records in that stage to display.') diff --git a/quality_control_issue/models/qc_problem.py b/quality_control_issue/models/qc_problem.py new file mode 100644 index 000000000..429154ba3 --- /dev/null +++ b/quality_control_issue/models/qc_problem.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + +AVAILABLE_PRIORITIES = [ + ('0', 'Normal'), + ('1', 'Low'), + ('2', 'High'), + ('3', 'Very High'), +] + + +class QcProblem(models.Model): + _name = "qc.problem" + _description = "Quality Control Problem Tracking" + _inherit = "mail.thread" + + def _get_default_stage_id(self): + """ Gives default stage_id """ + team_id = self.env['qc.team']._get_default_qc_team_id( + user_id=self.env.uid) + return self.stage_find([], team_id, [('fold', '=', False)]) + + @api.multi + def _read_group_stage_ids(self, domain, read_group_order=None, + access_rights_uid=None): + access_rights_uid = access_rights_uid or self._uid + stage_obj = self.env['qc.stage'] + search_domain = [] + qc_team_id = self.env.context.get('default_qc_team_id') or False + if qc_team_id: + search_domain += ['|', ('id', 'in', self.ids)] + search_domain += ['|', ('qc_team_id', '=', qc_team_id)] + search_domain += [('qc_team_id', '=', False)] + else: + search_domain += ['|', ('id', 'in', self.ids)] + search_domain += [('qc_team_id', '=', False)] + # perform search + stage_ids = stage_obj._search(search_domain, + access_rights_uid=access_rights_uid) + result = [stage.name_get()[0] for stage in + stage_obj.browse(stage_ids)] + # restore order of the search + result.sort( + lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) + + fold = {} + for stage in stage_obj.browse(stage_ids): + fold[stage.id] = stage.fold or False + return result, fold + + @api.one + @api.depends('issue_ids') + def _compute_count(self): + self.issue_count = len(self.issue_ids) + + name = fields.Char() + notes = fields.Text() + issue_ids = fields.Many2many( + comodel_name="qc.issue", string="QC Issues", + relation="qc_issue_problem_rel", column1="qc_problem_id", + column2="qc_issue_id") + problem_group_id = fields.Many2one( + comodel_name="qc.problem.group", string="Problem Group") + issue_count = fields.Integer( + string="Issues", compute=_compute_count, store=True) + color = fields.Integer(string='Color Index') + priority = fields.Selection( + selection=AVAILABLE_PRIORITIES, string='Rating', index=True) + stage_id = fields.Many2one( + comodel_name="qc.stage", string='Stage', track_visibility='onchange', + select=True, default=_get_default_stage_id, + domain="['|', ('qc_team_id', '=', False), " + "('qc_team_id', '=', qc_team_id)]") + qc_team_id = fields.Many2one( + comodel_name='qc.team', string='QC Team', + default=lambda self: self.env[ + 'qc.team'].sudo()._get_default_qc_team_id(user_id=self.env.uid), + index=True, track_visibility='onchange') + company_id = fields.Many2one( + comodel_name='res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) + _group_by_full = { + 'stage_id': _read_group_stage_ids + } + + def stage_find(self, cases, team_id, domain=None, order='sequence'): + """ Override of the base.stage method + Parameter of the stage search taken from the problem: + - team_id: if set, stages must belong to this team or + be a default stage; if not set, stages must be default + stages + """ + team_ids = set() + if team_id: + team_ids.add(team_id) + for problem in cases: + if problem.team_id: + team_ids.add(problem.team_id.id) + search_domain = [] + if team_ids: + search_domain += [('|')] * (len(team_ids) - 1) + for team_id in team_ids: + search_domain.append(('qc_team_id', '=', team_id.id)) + search_domain += list(domain) + # perform search, return the first found + stage_ids = self.env['qc.stage'].search( + search_domain, order=order, limit=1) + if stage_ids: + return stage_ids[0] + return False diff --git a/quality_control_issue/models/qc_problem_group.py b/quality_control_issue/models/qc_problem_group.py new file mode 100644 index 000000000..c2468cb74 --- /dev/null +++ b/quality_control_issue/models/qc_problem_group.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import fields, models + + +class QcProblemGroup(models.Model): + _name = "qc.problem.group" + _description = "Quality Control Problem Tracking Groups" + + name = fields.Char() + problem_ids = fields.One2many( + comodel_name="qc.problem", inverse_name="problem_group_id") + company_id = fields.Many2one( + comodel_name='res.company', string='Company', required=True, + default=lambda self: self.env.user.company_id) diff --git a/quality_control_issue/models/qc_stage.py b/quality_control_issue/models/qc_stage.py new file mode 100644 index 000000000..1b237e255 --- /dev/null +++ b/quality_control_issue/models/qc_stage.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import api, fields, models + +AVAILABLE_PRIORITIES = [ + ('0', 'Normal'), + ('1', 'Low'), + ('2', 'High'), + ('3', 'Very High'), +] + + +class QualityControlStage(models.Model): + _name = "qc.stage" + _rec_name = 'name' + _order = "sequence, name, id" + + @api.model + def default_get(self, fields): + """ Hack : when going from the kanban view, creating a stage with a + qc team in context should not create a stage for the current team only. + """ + ctx = dict(self.env.context) + if ctx.get('default_qc_team_id') and not ctx.get('some_context'): + ctx.pop('default_qc_team_id') + return super(QualityControlStage, + self.with_context(ctx)).default_get(fields) + + name = fields.Char('Stage Name', required=True) + sequence = fields.Integer( + string='Sequence', help="Used to order stages. Lower is better.", + default=1) + qc_team_id = fields.Many2one( + comodel_name='qc.team', string='Quality Control Team', + ondelete='set null') + fold = fields.Boolean( + string='Folded in Pipeline', default=False, + help='This stage is folded in the kanban view when there are no ' + 'records in that stage to display.') diff --git a/quality_control_issue/security/ir.model.access.csv b/quality_control_issue/security/ir.model.access.csv new file mode 100644 index 000000000..eaf2e3511 --- /dev/null +++ b/quality_control_issue/security/ir.model.access.csv @@ -0,0 +1,11 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_user_qc_issue,qc.issue.user,quality_control_issue.model_qc_issue,quality_control.group_quality_control_user,1,1,1,0 +access_manager_qc_issue,qc.issue.manager,quality_control_issue.model_qc_issue,quality_control.group_quality_control_manager,1,1,1,1 +access_user_qc_problem_group,qc.problem.group.user,quality_control_issue.model_qc_problem_group,quality_control.group_quality_control_user,1,0,0,0 +access_manager_qc_problem_group,qc.problem.group.manager,quality_control_issue.model_qc_problem_group,quality_control.group_quality_control_manager,1,1,1,1 +access_user_qc_problem,qc.problem.user,quality_control_issue.model_qc_problem,quality_control.group_quality_control_user,1,1,1,0 +access_manager_qc_team,qc.problem.manager,quality_control_issue.model_qc_problem,quality_control.group_quality_control_manager,1,1,1,1 +access_user_qc_stage,qc.stage.user,quality_control_issue.model_qc_stage,quality_control.group_quality_control_user,1,0,0,0 +access_manager_qc_stage,qc.stage.manager,quality_control_issue.model_qc_stage,quality_control.group_quality_control_manager,1,1,1,1 +access_user_qc_issue_stage,qc.issue.stage.user,quality_control_issue.model_qc_issue_stage,quality_control.group_quality_control_user,1,0,0,0 +access_manager_qc_issue_stage,qc.issue.stage.manager,quality_control_issue.model_qc_issue_stage,quality_control.group_quality_control_manager,1,1,1,1 diff --git a/quality_control_issue/security/quality_control_issue_security.xml b/quality_control_issue/security/quality_control_issue_security.xml new file mode 100644 index 000000000..014abff4e --- /dev/null +++ b/quality_control_issue/security/quality_control_issue_security.xml @@ -0,0 +1,22 @@ + + + + + + qc.issue multi-company + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + qc.issue multi-company + + + ['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])] + + + + diff --git a/quality_control_issue/static/description/icon.png b/quality_control_issue/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..e0aa80bcee2e5b2f7ef001921c947ec999f9578d GIT binary patch literal 7121 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 + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/quality_control_issue/views/qc_issue_view.xml b/quality_control_issue/views/qc_issue_view.xml new file mode 100644 index 000000000..0648932ca --- /dev/null +++ b/quality_control_issue/views/qc_issue_view.xml @@ -0,0 +1,175 @@ + + + + + + + qc.issue.tree + qc.issue + + + + + + + + + + + + + qc.issue.form + qc.issue + +
+
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+ + + qc.issue.kanban + qc.issue + + + + + + +
+ +
+
+ +
+ Product:

+ Qty:

+ Location: +

+ Problems: + + ; + + +
+
+
+
+
+
+
+
+ + + qc.issue.serch + qc.issue + + + + + + + + + + + + + + + + + + + + QC Issues + ir.actions.act_window + qc.issue + form + kanban,tree,form + + + + + + +
diff --git a/quality_control_issue/views/qc_problem_group_view.xml b/quality_control_issue/views/qc_problem_group_view.xml new file mode 100644 index 000000000..7a5a0364f --- /dev/null +++ b/quality_control_issue/views/qc_problem_group_view.xml @@ -0,0 +1,48 @@ + + + + + + + qc.problem.group.tree + qc.problem.group + + + + + + + + + qc.problem.group.form + qc.problem.group + +
+ + + + + + + + + + +
+
+
+ + + Problem groups + ir.actions.act_window + qc.problem.group + form + + + + +
diff --git a/quality_control_issue/views/qc_problem_view.xml b/quality_control_issue/views/qc_problem_view.xml new file mode 100644 index 000000000..d86ca46fc --- /dev/null +++ b/quality_control_issue/views/qc_problem_view.xml @@ -0,0 +1,136 @@ + + + + + + + qc.problem.tree + qc.problem + + + + + + + + + + + qc.problem.form + qc.problem + +
+
+ + +
+ + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ + + qc.problem.kanban + qc.problem + + + + + + + + +
+ +
+
+ +
+

+ issues + +
+
+
+
+
+
+
+
+ + + qc.problem.serch + qc.problem + + + + + + + + + + + + + + + + + Problem Tracking + ir.actions.act_window + qc.problem + form + kanban,tree,form + + + + + + +
diff --git a/quality_control_issue/views/qc_team_dashboard_view.xml b/quality_control_issue/views/qc_team_dashboard_view.xml new file mode 100644 index 000000000..99bc0376c --- /dev/null +++ b/quality_control_issue/views/qc_team_dashboard_view.xml @@ -0,0 +1,56 @@ + + + + + + Issues by team + qc.issue + kanban,tree,form,pivot + { + 'search_default_qc_team_id': [active_id], + 'default_qc_team_id': active_id, + 'default_user_id': uid, + } + + +

Manage Quality Control Issues through your team flow.

+
+
+ + + Problem tracking + qc.problem + kanban,tree,form,pivot + { + 'search_default_qc_team_id': [active_id], + 'default_qc_team_id': active_id, + 'default_user_id': uid, + } + + +

Track problems through your team flow.

+
+
+ + + qc.team.dashboard - quality_control_issue + qc.team + + + + + + + + + + + + + +