[ADD] stock_inventory_verification_request

This commit is contained in:
lreficent
2017-02-17 10:54:52 +01:00
committed by Jordi Ballester Alomar
parent a5dccd08b8
commit f5cd970020
11 changed files with 523 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
.. 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
====================================
Stock Inventory Verification Request
====================================
Adds the capability to request a Slot Verification when a inventory is
'Pending to Approve'. When asked from Inventory Adjustment, which have
discrepancies over the threshold for the location, a Slot Verification
Request will be created for each line that exceed the maximum discrepancy
allowed.
The Inventory Manager can then confirm the Slot verification and start to
check the involved Inventory Lines and Moves to find out some possible mistake
or problem.
Usage
=====
In order to use this module act as follow:
* From a Inventory Adjustment in state 'Pending to Approve' click in the
button 'Request Verification'. This will create all the Slot Verification
Request needed.
* Go to 'Inventory / Inventory Control / Slot Verification Request'
* Go to a Slot Verification Request 'Waiting Actions' and confirm it.
* You can now check the involved lines and moves to help you.
* Once you have found the problem and you have fixed it 'Mark as Solved' the
Verification.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/153/9.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/stock-logistics-warehouse/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.
Images
------
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
Contributors
------------
* Lois Rilo Antelo <lois.rilo@eficent.com>
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.

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import models

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Stock Inventory Verification Request",
"summary": "Adds the capability to request a Slot Verification when "
"a inventory is Pending to Approve",
"version": "9.0.1.0.0",
"author": "Eficent, "
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Warehouse Management",
"depends": ["stock_inventory_discrepancy",
"mail"],
"data": [
'views/stock_slot_verification_request_view.xml',
'views/stock_inventory_view.xml',
'data/slot_verification_request_sequence.xml',
'security/ir.model.access.csv'
],
"license": "AGPL-3",
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,15 @@
<?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 noupdate="1">
<record id="seq_slot_verification_request" model="ir.sequence">
<field name="name">Slot Verification Request</field>
<field name="code">stock.slot.verification.request</field>
<field name="prefix">SVR/%(range_year)s/</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
</odoo>

View File

@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import stock_slot_verification_request
from . import stock_inventory

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import _, api, fields, models
class StockInventory(models.Model):
_inherit = 'stock.inventory'
requested_verification = fields.Boolean(string='Requested Verification?',
default=False, copy=False)
slot_verification_ids = fields.One2many(
comodel_name='stock.slot.verification.request',
string='Slot Verification Requests', inverse_name='inventory_id')
@api.multi
def action_request_verification(self):
self.requested_verification = True
for line in self.line_ids:
if line.discrepancy_threshold and (line.discrepancy_percent >
line.discrepancy_threshold):
self.env['stock.slot.verification.request'].create({
'inventory_id': self.id,
'inventory_line_id': line.id,
'location_id': line.location_id.id,
'state': 'wait',
'product_id': line.product_id.id,
})
class StockInventoryLine(models.Model):
_inherit = 'stock.inventory.line'
# TODO: make this work
slot_verification_ids = fields.One2many(
comodel_name='stock.slot.verification.request',
inverse_name='inventory_line_id',
string='Slot Verification Request')
@api.multi
def action_open_svr(self):
'''
Open the corresponding Slot Verification Request directly from the
Inventory Lines.
'''
request_svr_ids = []
for line in self:
request_svr_ids += line.slot_verification_ids.ids
domain = [('id', 'in', request_svr_ids)]
return {'name': _('Slot Verification Request'),
'type': 'ir.actions.act_window',
'res_model': 'stock.slot.verification.request',
'view_type': 'form',
'view_mode': 'tree,form',
'domain': domain}

View File

@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from openerp import fields, models, api
class SlotVerificationRequest(models.Model):
_name = 'stock.slot.verification.request'
_inherit = 'mail.thread'
@api.model
def create(self, vals):
vals['name'] = self.env['ir.sequence'].next_by_code(
'stock.slot.verification.request') or ''
return super(SlotVerificationRequest, self).create(vals)
@api.one
def _count_involved_moves(self):
self.involved_move_count = len(self.involved_move_ids)
@api.one
def _count_involved_inv_lines(self):
self.involved_inv_line_count = len(self.involved_inv_line_ids)
name = fields.Char(string='Name', readonly=True)
inventory_id = fields.Many2one(comodel_name='stock.inventory',
string='Inventory Adjustment',
readonly=True)
inventory_line_id = fields.Many2one(comodel_name='stock.inventory.line',
string='Inventory Line',
readonly=True)
location_id = fields.Many2one(comodel_name='stock.location',
string='Location',
required=True)
state = fields.Selection(selection=[
('wait', 'Waiting Actions'),
('open', 'In Progress'),
('cancelled', 'Cancelled'),
('done', 'Solved')
], string='Status', default='wait')
responsible_id = fields.Many2one(comodel_name='res.users',
string='Assigned to')
product_id = fields.Many2one(comodel_name='product.product',
string='Product', required=True)
notes = fields.Text('Notes')
involved_move_ids = fields.Many2many(
comodel_name='stock.move',
relation='slot_verification_move_involved_rel',
column1='slot_verification_request_id',
column2='move_id',
string='Involved Stock Moves')
involved_move_count = fields.Integer(compute=_count_involved_moves)
involved_inv_line_ids = fields.Many2many(
comodel_name='stock.inventory.line',
relation='slot_verification_inv_line_involved_rel',
column1='slot_verification_request_id',
column2='inventory_line_id',
string='Involved Inventory Lines')
involved_inv_line_count = fields.Integer(compute=_count_involved_inv_lines)
@api.model
def _get_involved_moves_domain(self):
domain = [('product_id', '=', self.product_id.id), '|',
('location_id', '=', self.location_id.id),
('location_dest_id', '=', self.location_id.id)]
return domain
@api.model
def _get_involved_lines_domain(self):
domain = [('product_id', '=', self.product_id.id),
('location_id', '=', self.location_id.id)]
return domain
@api.model
def _get_involved_lines_and_locations(self):
involved_moves = self.env['stock.move'].search(
self._get_involved_moves_domain())
involved_lines = self.env['stock.inventory.line'].search(
self._get_involved_lines_domain())
return involved_moves, involved_lines
@api.one
def action_confirm(self):
self.state = 'open'
involved_moves, involved_lines = \
self._get_involved_lines_and_locations()
self.involved_move_ids = involved_moves
self.involved_inv_line_ids = involved_lines
return True
@api.one
def action_cancel(self):
self.state = 'cancelled'
return True
@api.one
def action_solved(self):
self.state = 'done'
return True
@api.multi
def action_view_moves(self):
action = self.env.ref('stock.action_move_form2')
result = action.read()[0]
result['context'] = {}
moves_ids = sum([svr.involved_move_ids.ids for svr in self], [])
if len(moves_ids) > 1:
result['domain'] = \
"[('id','in',[" + ','.join(map(str, moves_ids)) + "])]"
elif len(moves_ids) == 1:
res = self.env.ref('stock.view_move_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = moves_ids and moves_ids[0] or False
return result
@api.multi
def action_view_inv_lines(self):
action = self.env.ref(
'stock_inventory_verification_request.action_inv_adj_line_tree')
result = action.read()[0]
result['context'] = {}
line_ids = sum([svr.involved_inv_line_ids.ids for svr in self], [])
if len(line_ids) > 1:
result['domain'] = \
"[('id','in',[" + ','.join(map(str, line_ids)) + "])]"
elif len(line_ids) == 1:
res = self.env.ref('stock_inventory_verification_request.'
'view_inventory_line_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = line_ids and line_ids[0] or False
return result

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_slot_verification_request_user,stock.slot.verification.request user,model_stock_slot_verification_request,stock.group_stock_user,1,0,0,0
access_slot_verification_request_manager,stock.slot.verification.request manager,model_stock_slot_verification_request,stock.group_stock_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_slot_verification_request_user stock.slot.verification.request user model_stock_slot_verification_request stock.group_stock_user 1 0 0 0
3 access_slot_verification_request_manager stock.slot.verification.request manager model_stock_slot_verification_request stock.group_stock_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,102 @@
<?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="view_inventory_form" model="ir.ui.view">
<field name="name">Inventory form view - SVR extension </field>
<field name="model">stock.inventory</field>
<field name="inherit_id" ref="stock.view_inventory_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='action_done']"
position="after">
<button name="action_request_verification"
string="Request Verification" type="object"
class="oe_highlight"
attrs="{'invisible': ['|',('state', '!=', 'pending'),('requested_verification', '=', True)]}"
groups="stock.group_stock_manager"/>
</xpath>
<field name="name" position="after">
<field name="requested_verification" invisible="1"/>
</field>
<notebook position="inside">
<page string="Slot Verification Requests"
groups="stock.group_stock_manager">
<group>
<field name="slot_verification_ids" nolabel="1"/>
</group>
</page>
</notebook>
<xpath expr="//field[@name='line_ids']/tree/field[@name='discrepancy_threshold']"
position="after">
<field name="slot_verification_ids" invisible="1"/>
<button string="Slot Verification Request"
attrs="{'invisible': [('slot_verification_ids', '=', [])]}"
name="action_open_svr"
type="object"
icon="gtk-open"/>
</xpath>
</field>
</record>
<record id="view_inventory_line_form" model="ir.ui.view">
<field name="name">Inventory Adjustment Line Form View</field>
<field name="model">stock.inventory.line</field>
<field name="arch" type="xml">
<form string="Inventory Line">
<sheet>
<div class="oe_title">
<h3>Inventory Adjustment Line <field name="id"/></h3>
</div>
<group>
<group col="2">
<field name="product_id" readonly="1"/>
<field name="inventory_id" readonly="1"/>
<field name="state"/>
<field name="create_date" readonly="1"/>
<field name="location_id" readonly="1"/>
<field name="package_id" readonly="1"/>
<field name="partner_id" readonly="1"/>
<field name="prod_lot_id" readonly="1"/>
<field name="company_id"/>
</group>
<group col="2">
<field name="theoretical_qty"/>
<field name="product_qty" readonly="1"/>
<field name="product_uom_id" readonly="1"/>
<field name="discrepancy_qty"/>
<label for="discrepancy_percent"/>
<div>
<field name="discrepancy_percent" class="oe_inline"/> %
</div>
<label for="discrepancy_threshold"/>
<div>
<field name="discrepancy_threshold" class="oe_inline"/> %
</div>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_inventory_line_tree" model="ir.ui.view">
<field name="name">Inventory Line tree view - discrepancy extension</field>
<field name="model">stock.inventory.line</field>
<field name="inherit_id" ref="stock.stock_inventory_line_tree"/>
<field name="arch" type="xml">
<field name="location_id" position="after">
<field name="create_date" readonly="1"/>
</field>
</field>
</record>
<record id="action_inv_adj_line_tree" model="ir.actions.act_window">
<field name="name">Open Inventory Adjustment Lines</field>
<field name="res_model">stock.inventory.line</field>
<field name="view_type">form</field>
<field name="view_id" ref="stock.stock_inventory_line_tree"/>
</record>
</odoo>

View File

@@ -0,0 +1,103 @@
<?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_slot_verification_request_tree_view" model="ir.ui.view">
<field name="name">stock.slot.verification.request.tree</field>
<field name="model">stock.slot.verification.request</field>
<field name="arch" type="xml">
<tree string="Stock Slot Verification Request">
<field name="name"/>
<field name="location_id"/>
<field name="product_id"/>
<field name="create_uid" readonly="1"/>
<field name="create_date" readonly="1"/>
<field name="responsible_id"/>
<field name="inventory_id"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="stock_slot_verification_request_form_view" model="ir.ui.view">
<field name="name">stock.slot.verification.request.form</field>
<field name="model">stock.slot.verification.request</field>
<field name="arch" type="xml">
<form string="Stock Slot Verification Request">
<header>
<button name="action_confirm"
type="object" states="wait" string="Confirm"
class="oe_highlight" />
<button name="action_solved"
type="object" states="open" string="Mark as Solved"/>
<button name="action_cancel"
type="object" states="open"
string="Mark as Cancelled"/>
<field name="state" widget="statusbar"
statusbar_visible="wait,open,done"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box"
attrs="{'invisible':
[('state', 'not in', ('open'))]}">
<button name="action_view_moves"
type="object" class="oe_stat_button"
icon="fa-building-o">
<field name="involved_move_count"
widget="statinfo"
help="Stock Moves related to the given location and product."
modifiers="{'readonly': true}"
string="Stock Moves Involved"/>
</button>
<button name="action_view_inv_lines"
type="object" class="oe_stat_button"
icon="fa-building-o">
<field name="involved_inv_line_count"
widget="statinfo"
help="Inventory Adjustment Lines related to the given location and product."
modifiers="{'readonly': true}"
string="Inv. Adj. Lines Involved"/>
</button>
</div>
<div class="oe_title">
<label string="Slot Verification Request"/>
<h1>
<field name="name"/>
</h1>
</div>
<group>
<group>
<field name="location_id"/>
<field name="product_id"/>
<field name="create_uid" readonly="1"/>
<field name="create_date" readonly="1"/>
<field name="responsible_id"/>
<field name="inventory_id"/>
<field name="inventory_line_id"/>
</group>
<group>
<field name="notes"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread" />
</div>
</form>
</field>
</record>
<act_window id="action_slot_verification_request"
name="Stock Slot Verification Request"
res_model="stock.slot.verification.request"
view_mode="tree,form" />
<menuitem id="menu_slot_verification_request"
name="Slot Verification Request"
parent="stock.menu_stock_inventory_control"
sequence="40"
action="action_slot_verification_request" />
</odoo>