mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[ADD] stock_inventory_verification_request
This commit is contained in:
committed by
Jordi Ballester Alomar
parent
a5dccd08b8
commit
f5cd970020
72
stock_inventory_verification_request/README.rst
Normal file
72
stock_inventory_verification_request/README.rst
Normal 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.
|
||||
6
stock_inventory_verification_request/__init__.py
Normal file
6
stock_inventory_verification_request/__init__.py
Normal 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
|
||||
25
stock_inventory_verification_request/__openerp__.py
Normal file
25
stock_inventory_verification_request/__openerp__.py
Normal 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,
|
||||
}
|
||||
@@ -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>
|
||||
7
stock_inventory_verification_request/models/__init__.py
Normal file
7
stock_inventory_verification_request/models/__init__.py
Normal 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
|
||||
@@ -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}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
BIN
stock_inventory_verification_request/static/description/icon.png
Normal file
BIN
stock_inventory_verification_request/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.2 KiB |
@@ -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>
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user