[IMP] quality_control_issue: add scrap feature.

This commit is contained in:
lreficent
2017-07-28 12:08:40 +02:00
committed by Jordi Ballester Alomar
parent e16506f189
commit 4075ce1ffe
10 changed files with 195 additions and 20 deletions

View File

@@ -2,3 +2,4 @@
# Add a repository url and branch if you need a forked version # Add a repository url and branch if you need a forked version
product-attribute product-attribute
stock-logistics-warehouse stock-logistics-warehouse
stock-logistics-workflow

View File

@@ -6,17 +6,59 @@
Quality Control Issue Quality Control Issue
===================== =====================
WIP
This module extends the functionality of quality Control to allow you to This module extends the functionality of quality Control to allow you to
report and manage quality control issues. report and manage quality control issues.
Configuration
=============
To configure this module in order to take advantage of the kanban views you
need to create the stages for *issues* and *problems*. To **create** stages in
any kanban view click on *Add New Column*. Then you can **reorder** the stages
just dragging them.
In created stages you can **configure** them clicking on the gear button that
appears at the right of the stage name and clicking on *Edit*. Note the
following behaviors:
* You can set a *Quality Control Team*.
- Stages with no team set will be shared by all teams.
- Stages with a team associated will be only available for that specific
team.
* In Issue Stages you can also relate a *QC State* to the stage.
- When you move to a different stage an issue with *QC state* defined the
state of the issue will also change according to it.
- The other way around, if you change the state, the system will look for
an appropriate stage and if existing the issue will be move to that stage.
- If you change the *QC team* of an issue, the system will get the default
stage for that team and apply it to the issue.
Usage Usage
===== =====
To use this module, you need to: To use Quality Control Issues, you need to:
#. Go to *Quality Control > Issues > QC Issues*. #. Go to *Quality Control > Issues > QC Issues* or to *Quality Control >
Dashboard* and click on *Issues* in any of your teams.
#. Click on create to report an issue.
#. Select the product and quantity for the issue. Optionally you can specify
a location and relate the issue to some *Problem*.
To manage your Quality Control Problems, you have to:
#. Go to *Quality Control > Problem Tracking > Problems* or to *Quality
Control > Dashboard* and click on *Problems* in any of your teams.
Issue Dispositions:
-------------------
You can perform the following actions in quality control issues 'in progress':
* Scrap: Click on *Scrap Products* button.
* Create RMA: Install `rma_quality_control_issue` and see instructions there.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot :alt: Try me on Runbot
@@ -28,9 +70,7 @@ Known issues / Roadmap
Todo: Todo:
----- -----
* Add Dispositions: RMA, scrap, rework... * Add more dispositions: repair, refurbish...
* reference to PO, MO, QC...
* Link to Problem tracking...
Bug Tracker Bug Tracker
=========== ===========
@@ -52,6 +92,7 @@ Contributors
------------ ------------
* Lois Rilo <lois.rilo@eficent.com> * Lois Rilo <lois.rilo@eficent.com>
* Jordi Ballester Alomar <jordi.ballester@eficent.com>
Maintainer Maintainer
---------- ----------

View File

@@ -11,7 +11,12 @@
"license": "AGPL-3", "license": "AGPL-3",
"application": False, "application": False,
"installable": True, "installable": True,
"depends": ["quality_control", "quality_control_team", "stock"], "depends": [
"quality_control",
"quality_control_team",
"stock",
"stock_scrap",
],
"data": [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",
"security/quality_control_issue_security.xml", "security/quality_control_issue_security.xml",
@@ -21,5 +26,6 @@
"views/qc_problem_view.xml", "views/qc_problem_view.xml",
"views/qc_problem_group_view.xml", "views/qc_problem_group_view.xml",
"views/qc_team_dashboard_view.xml", "views/qc_team_dashboard_view.xml",
"views/stock_scrap_view.xml",
], ],
} }

View File

@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L. # Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import stock_scrap
from . import qc_stage from . import qc_stage
from . import qc_problem from . import qc_problem
from . import qc_problem_group from . import qc_problem_group

View File

@@ -2,7 +2,8 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L. # Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import api, fields, models from openerp import api, fields, models, _
from openerp.exceptions import UserError
import openerp.addons.decimal_precision as dp import openerp.addons.decimal_precision as dp
@@ -11,6 +12,12 @@ class QualityControlIssue(models.Model):
_description = "Quality Control Issue" _description = "Quality Control Issue"
_inherit = "mail.thread" _inherit = "mail.thread"
@api.multi
def _compute_stock_scrap_qty(self):
for rec in self:
rec.stock_scrap_qty = sum(
self.stock_scrap_ids.mapped('scrap_qty'))
@api.model @api.model
def create(self, vals): def create(self, vals):
vals['name'] = self.env['ir.sequence'].next_by_code( vals['name'] = self.env['ir.sequence'].next_by_code(
@@ -61,7 +68,7 @@ class QualityControlIssue(models.Model):
("progress", "In Progress"), ("progress", "In Progress"),
("done", "Done"), ("done", "Done"),
("cancel", "Cancel")], default="new", ("cancel", "Cancel")], default="new",
track_visibility='onchange') track_visibility='onchange', readonly=True)
product_id = fields.Many2one( product_id = fields.Many2one(
comodel_name="product.product", string="Product", comodel_name="product.product", string="Product",
readonly=True, states={"new": [("readonly", False)]}, required=True) readonly=True, states={"new": [("readonly", False)]}, required=True)
@@ -111,6 +118,10 @@ class QualityControlIssue(models.Model):
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', string='Company', required=True, comodel_name='res.company', string='Company', required=True,
default=lambda self: self.env.user.company_id) default=lambda self: self.env.user.company_id)
stock_scrap_ids = fields.One2many(
comodel_name='stock.scrap', string='Scraps',
inverse_name='qc_issue_id')
stock_scrap_qty = fields.Integer(compute=_compute_stock_scrap_qty)
_group_by_full = { _group_by_full = {
'stage_id': _read_group_stage_ids 'stage_id': _read_group_stage_ids
@@ -131,18 +142,47 @@ class QualityControlIssue(models.Model):
team_ids.add(issue.team_id.id) team_ids.add(issue.team_id.id)
search_domain = [] search_domain = []
if team_ids: if team_ids:
search_domain += [('|')] * (len(team_ids) - 1) search_domain += [('|')] * (len(team_ids))
search_domain.append(('qc_team_id', '=', False))
for team_id in team_ids: for team_id in team_ids:
search_domain.append(('qc_team_id', '=', team_id)) search_domain.append(('qc_team_id', '=', team_id))
else:
search_domain.append(('qc_team_id', '=', False))
search_domain += list(domain) search_domain += list(domain)
# perform search, return the first found # perform search, return the first found
stage = self.env['qc.issue.stage'].search( stage = self.env['qc.issue.stage'].search(
search_domain, order=order, limit=1) search_domain, order=order, limit=1)
return stage return stage
@api.multi
def write(self, vals):
stage_obj = self.env['qc.issue.stage']
state = vals.get('state')
if state:
if len(self.mapped('qc_team_id')) > 1:
raise UserError(_(
"Every issue must have the same QC team to perform this "
"action."))
team = self[0].qc_team_id
stage = self.issue_stage_find([], team, [('state', '=', state)])
if stage:
vals.update({'stage_id': stage.id})
return super(QualityControlIssue, self).write(vals)
team_id = vals.get('qc_team_id')
if team_id is not None:
team = self.env['qc.team'].browse(team_id)
stage = self.issue_stage_find([], team, [('fold', '=', False)])
if stage:
vals.update({'stage_id': stage.id})
stage_id = vals.get('stage_id')
if stage_id:
state = stage_obj.browse(stage_id).state
if state:
vals.update({'state': state})
return super(QualityControlIssue, self).write(vals)
@api.multi @api.multi
def action_confirm(self): def action_confirm(self):
self._check_required_fields()
self.write({'state': 'progress'}) self.write({'state': 'progress'})
@api.multi @api.multi
@@ -170,7 +210,38 @@ class QualityControlIssue(models.Model):
self.product_id = product self.product_id = product
self.product_uom = product.product_tmpl_id.uom_id self.product_uom = product.product_tmpl_id.uom_id
@api.onchange("stage_id") @api.multi
def _onchange_stage_id(self): def scrap_products(self):
if self.stage_id.state: self.ensure_one()
self.state = self.stage_id.state return {
'name': _('Scrap'),
'view_type': 'form',
'view_mode': 'form',
'res_model': 'stock.scrap',
'view_id': self.env.ref('stock_scrap.stock_scrap_form_view2').id,
'type': 'ir.actions.act_window',
'context': {
'default_qc_issue_id': self.id,
'default_location_id': self.location_id.id,
'default_product_id': self.product_id.id,
'default_scrap_qty': self.product_qty,
'default_product_uom_id': self.product_uom.id,
'default_lot_id': self.lot_id.id,
},
'target': 'new',
}
@api.multi
def action_view_stock_scrap(self):
action = self.env.ref('stock_scrap.action_stock_scrap')
result = action.read()[0]
lines = self.stock_scrap_ids
# choose the view_mode accordingly
if len(lines) != 1:
result['domain'] = "[('id', 'in', " + \
str(lines.ids) + ")]"
elif len(lines) == 1:
res = self.env.ref('stock_scrap.stock_scrap_form_view', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = lines.id
return result

View File

@@ -40,5 +40,5 @@ class QualityControlIssueStage(models.Model):
help='This stage is folded in the kanban view when there are no ' help='This stage is folded in the kanban view when there are no '
'records in that stage to display.') 'records in that stage to display.')
state = fields.Selection( state = fields.Selection(
string="QC Status", string="QC State",
selection=lambda self: self.env['qc.issue']._fields['state'].selection) selection=lambda self: self.env['qc.issue']._fields['state'].selection)

View File

@@ -101,9 +101,12 @@ class QcProblem(models.Model):
team_ids.add(problem.team_id.id) team_ids.add(problem.team_id.id)
search_domain = [] search_domain = []
if team_ids: if team_ids:
search_domain += [('|')] * (len(team_ids) - 1) search_domain += [('|')] * (len(team_ids))
search_domain.append(('qc_team_id', '=', False))
for team_id in team_ids: for team_id in team_ids:
search_domain.append(('qc_team_id', '=', team_id)) search_domain.append(('qc_team_id', '=', team_id))
else:
search_domain.append(('qc_team_id', '=', False))
search_domain += list(domain) search_domain += list(domain)
# perform search, return the first found # perform search, return the first found
stage = self.env['qc.stage'].search( stage = self.env['qc.stage'].search(

View File

@@ -0,0 +1,12 @@
# -*- 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 QualityControlIssueStage(models.Model):
_inherit = "stock.scrap"
qc_issue_id = fields.Many2one(
comodel_name="qc.issue", string="Quality Control Issue")

View File

@@ -29,7 +29,10 @@
string="Confirm" class="oe_highlight" /> string="Confirm" class="oe_highlight" />
<button name="action_done" <button name="action_done"
type="object" states="progress" type="object" states="progress"
string="Set to Done" class="oe_highlight" /> string="Set to Done" class="oe_highlight"/>
<button name="scrap_products"
string="Scrap Products" type="object"
states="progress"/>
<button name="action_cancel" <button name="action_cancel"
type="object" states="new,progress" type="object" states="new,progress"
string="Cancel"/> string="Cancel"/>
@@ -39,7 +42,14 @@
</header> </header>
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<!--To be inhereted by other modules.--> <button type="object" name="action_view_stock_scrap"
class="oe_stat_button"
icon="fa-recycle"
context="{'default_qc_issue_id': active_id}">
<field name="stock_scrap_qty"
widget="statinfo"
string="Scrapped products"/>
</button>
</div> </div>
<div class="oe_title"> <div class="oe_title">
<label string="Quality Control Issue"/> <label string="Quality Control Issue"/>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="stock_scrap_form_view" model="ir.ui.view">
<field name="name">stock.scrap.form - quality_control_issue</field>
<field name="model">stock.scrap</field>
<field name="inherit_id" ref="stock_scrap.stock_scrap_form_view"/>
<field name="arch" type="xml">
<field name="owner_id" position="after">
<field name="qc_issue_id" attrs="{'invisible': [('qc_issue_id', '=', False)]}"/>
</field>
</field>
</record>
<record id="stock_scrap_form_view2" model="ir.ui.view">
<field name="name">stock.scrap.form2 - quality_control_issue</field>
<field name="model">stock.scrap</field>
<field name="inherit_id" ref="stock_scrap.stock_scrap_form_view2"/>
<field name="arch" type="xml">
<field name="owner_id" position="after">
<field name="qc_issue_id" attrs="{'invisible': [('qc_issue_id', '=', False)]}"/>
</field>
</field>
</record>
</odoo>