[WIP] Reorganise action_consume wizard to start from mrp and clean op inventory wizards

bzr revid: jco@openerp.com-20140128151834-ni90kny7b2y6sr36
This commit is contained in:
Josse Colpaert 2014-01-28 16:18:34 +01:00
parent 47d04a43e1
commit 8ec0968f8d
11 changed files with 41 additions and 431 deletions

View File

@ -73,6 +73,7 @@ Dashboard / Reports for MRP will include:
'report/mrp_production_order_view.xml',
'board_manufacturing_view.xml',
'res_config_view.xml',
'wizard/stock_move_view.xml',
],
'demo': ['mrp_demo.xml'],
'test': [

View File

@ -103,26 +103,50 @@ class StockMove(osv.osv):
procurement_obj.signal_button_wait_done(cr, uid, procurement_ids)
return processed_ids
def action_consume(self, cr, uid, ids, product_qty, location_id=False, restrict_lot_id = False, default_values = None, context=None):
def action_consume(self, cr, uid, ids, product_qty, location_id=False, restrict_lot_id = False, restrict_partner_id = False,
consumed_for = False, context=None):
""" Consumed product with specific quantity from specific source location.
@param product_qty: Consumed product quantity
@param location_id: Source location
@return: Consumed lines
"""
if default_values is None:
default_values = {}
res = []
production_obj = self.pool.get('mrp.production')
uom_obj = self.pool.get('product.uom')
if product_qty <= 0:
raise osv.except_osv(_('Warning!'), _('Please provide proper quantity.'))
for move in self.browse(cr, uid, ids, context=context):
self.action_confirm(cr, uid, [move.id], context=context)
new_moves = super(StockMove, self).action_consume(cr, uid, [move.id], product_qty, location_id, restrict_lot_id = restrict_lot_id,
default_values = default_values, context=context)
if move.state == 'draft':
self.action_confirm(cr, uid, [move.id], context=context)
move_qty = move.product_qty
uom_qty = uom_obj._compute_qty(cr, uid, move.product_id.uom_id.id, product_qty, move.product_uom.id)
if move_qty <= 0:
raise osv.except_osv(_('Error!'), _('Cannot consume a move with negative or zero quantity.'))
quantity_rest = move.product_qty - uom_qty
if quantity_rest > 0:
ctx = context.copy()
if location_id:
ctx['source_location_id'] = location_id
res.append(self.split(cr, uid, move, move_qty - quantity_rest, restrict_lot_id=restrict_lot_id,
restrict_partner_id=restrict_partner_id, context=ctx))
#TODO need to add consumed_for here
else:
res.append(move.id)
if location_id:
self.write(cr, uid, [move.id], {'location_id': location_id, 'restrict_lot_id': restrict_lot_id,
'restrict_partner_id': restrict_partner_id,
'consumed_for': consumed_for}, context=context)
self.action_done(cr, uid, res, context=context)
production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
for prod in production_obj.browse(cr, uid, production_ids, context=context):
if prod.state == 'confirmed':
production_obj.force_production(cr, uid, [prod.id])
production_obj.signal_button_produce(cr, uid, production_ids)
for new_move in new_moves:
for new_move in res:
if new_move != move.id:
#This move is not already there in move lines of production order
production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})

View File

@ -23,6 +23,7 @@ import mrp_product_produce
import mrp_price
import mrp_workcenter_load
import change_production_qty
import stock_move
#import mrp_change_standard_price
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1899,41 +1899,6 @@ class stock_move(osv.osv):
self.action_done(cr, uid, res, context=context)
return res
def action_consume(self, cr, uid, ids, quantity, location_id=False, restrict_lot_id=False, default_values = None, context=None):
""" Consumed product with specific quantity from specific source location. This correspond to a split of the move (or write if the quantity to consume is >= than the quantity of the move) followed by an action_done
@param ids: ids of stock move object to be consumed
@param quantity : specify consume quantity (given in move UoM)
@param location_id : specify source location
@return: Consumed lines
"""
if default_values is None:
default_values = {}
uom_obj = self.pool.get('product.uom')
if context is None:
context = {}
if quantity <= 0:
raise osv.except_osv(_('Warning!'), _('Please provide proper quantity.'))
res = []
for move in self.browse(cr, uid, ids, context=context):
move_qty = move.product_qty
uom_qty = uom_obj._compute_qty(cr, uid, move.product_id.uom_id.id, quantity, move.product_uom.id)
if move_qty <= 0:
raise osv.except_osv(_('Error!'), _('Cannot consume a move with negative or zero quantity.'))
quantity_rest = move.product_qty - uom_qty
if quantity_rest > 0:
ctx = context.copy()
if location_id:
ctx['source_location_id'] = location_id
res.append(self.split(cr, uid, move, move_qty - quantity_rest, restrict_lot_id=restrict_lot_id,
default_values = default_values, context=ctx))
else:
res.append(move.id)
if location_id:
vals = default_values.copy()
vals.update({'location_id': location_id, 'restrict_lot_id': restrict_lot_id})
self.write(cr, uid, [move.id], vals, context=context)
self.action_done(cr, uid, res, context=context)
return res
def split(self, cr, uid, move, qty, restrict_lot_id=False, default_values = None, context=None):
""" Splits qty from move move into a new move

View File

@ -20,8 +20,6 @@
##############################################################################
import stock_move
import stock_inventory_merge
import stock_inventory_line_split
import stock_location_product
import stock_return_picking
import stock_change_product_qty

View File

@ -1,112 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import fields, osv
class stock_inventory_line_split(osv.osv_memory):
_inherit = "stock.move.split"
_name = "stock.inventory.line.split"
_description = "Split inventory lines"
_columns = {
'line_ids': fields.one2many('stock.inventory.line.split.lines', 'wizard_id', 'Serial Numbers'),
'line_exist_ids': fields.one2many('stock.inventory.line.split.lines', 'wizard_exist_id', 'Serial Numbers'),
}
def default_get(self, cr, uid, fields, context=None):
if context is None:
context = {}
record_id = context and context.get('active_id',False)
res = {}
line = self.pool.get('stock.inventory.line').browse(cr, uid, record_id, context=context)
if 'product_id' in fields:
res.update({'product_id':line.product_id.id})
if 'product_uom' in fields:
res.update({'product_uom': line.product_uom_id.id})
if 'qty' in fields:
res.update({'qty': line.product_qty})
return res
def split(self, cr, uid, ids, line_ids, context=None):
""" To split stock inventory lines according to serial numbers.
:param line_ids: the ID or list of IDs of inventory lines we want to split
"""
if context is None:
context = {}
assert context.get('active_model') == 'stock.inventory.line',\
'Incorrect use of the inventory line split wizard.'
prodlot_obj = self.pool.get('stock.production.lot')
ir_sequence_obj = self.pool.get('ir.sequence')
line_obj = self.pool.get('stock.inventory.line')
new_line = []
for data in self.browse(cr, uid, ids, context=context):
for inv_line in line_obj.browse(cr, uid, line_ids, context=context):
line_qty = inv_line.product_qty
quantity_rest = inv_line.product_qty
new_line = []
if data.use_exist:
lines = [l for l in data.line_exist_ids if l]
else:
lines = [l for l in data.line_ids if l]
for line in lines:
quantity = line.quantity
if quantity <= 0 or line_qty == 0:
continue
quantity_rest -= quantity
if quantity_rest < 0:
quantity_rest = quantity
break
default_val = {
'product_qty': quantity,
}
if quantity_rest > 0:
current_line = line_obj.copy(cr, uid, inv_line.id, default_val)
new_line.append(current_line)
if quantity_rest == 0:
current_line = inv_line.id
lot_id = False
if data.use_exist:
lot_id = line.lot_id.id
if not lot_id:
lot_id = prodlot_obj.create(cr, uid, {
'name': line.name,
'product_id': inv_line.product_id.id},
context=context)
line_obj.write(cr, uid, [current_line], {'prod_lot_id': lot_id})
prodlot = prodlot_obj.browse(cr, uid, lot_id)
update_val = {}
if quantity_rest > 0:
update_val['product_qty'] = quantity_rest
line_obj.write(cr, uid, [inv_line.id], update_val)
return new_line
class stock_inventory_split_lines(osv.osv_memory):
_inherit = "stock.move.split.lines"
_name = "stock.inventory.line.split.lines"
_description = "Inventory Split lines"
_columns = {
'wizard_id': fields.many2one('stock.inventory.line.split', 'Parent Wizard'),
'wizard_exist_id': fields.many2one('stock.inventory.line.split', 'Parent Wizard'),
}

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_split_in_lots_inherit" model="ir.ui.view">
<field name="name">Split Inventory Line</field>
<field name="model">stock.inventory.line.split</field>
<field name="arch" type="xml">
<form string="Split in Serial Numbers" version="7.0">
<group>
<field name="product_id" colspan="4" readonly="1"/>
<label for="qty"/>
<div>
<field name="qty" readonly="1"/>
<field name="product_uom" readonly="1"/>
</div>
<field name="use_exist"/>
</group>
<field name="line_ids" attrs="{'invisible':[('use_exist','=',True)]}">
<tree string="Lots Number" editable="bottom">
<field name="name" string="Lots"/>
<field name="quantity" />
</tree>
<form string="Lots Number" version="7.0">
<group>
<field name="name" string="Lots"/>
<field name="quantity" />
</group>
</form>
</field>
<field name="line_exist_ids" attrs="{'invisible':[('use_exist','!=',True)]}">
<tree string="Lots Number" editable="bottom">
<field name="lot_id" string="Lots" domain="[('product_id','=',parent.product_id)]"/>
<field name="quantity" />
</tree>
<form string="Lots Number" version="7.0">
<group>
<field name="lot_id" string="Lots" domain="[('product_id','=',parent.product_id)]"/>
<field name="quantity" />
</group>
</form>
</field>
<footer>
<button name="split_lot" string="Ok" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_view_stock_inventory_line_split" model="ir.actions.act_window">
<field name="name">Split inventory lines</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.inventory.line.split</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -1,91 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp.osv import fields, osv
from openerp.tools.translate import _
class stock_inventory_merge(osv.osv_memory):
_name = "stock.inventory.merge"
_description = "Merge Inventory"
def fields_view_get(self, cr, uid, view_id=None, view_type='form',
context=None, toolbar=False, submenu=False):
"""
Changes the view dynamically
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param context: A standard dictionary
@return: New arch of view.
"""
if context is None:
context={}
res = super(stock_inventory_merge, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar,submenu=False)
if context.get('active_model','') == 'stock.inventory' and len(context['active_ids']) < 2:
raise osv.except_osv(_('Warning!'),
_('Please select multiple physical inventories to merge in the list view.'))
return res
def do_merge(self, cr, uid, ids, context=None):
""" To merge selected Inventories.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: List of IDs selected
@param context: A standard dictionary
@return:
"""
invent_obj = self.pool.get('stock.inventory')
invent_line_obj = self.pool.get('stock.inventory.line')
invent_lines = {}
if context is None:
context = {}
for inventory in invent_obj.browse(cr, uid, context['active_ids'], context=context):
if inventory.state == "done":
raise osv.except_osv(_('Warning!'),
_('Merging is only allowed on draft inventories.'))
for line in inventory.inventory_line_id:
key = (line.location_id.id, line.product_id.id, line.product_uom_id.id)
if key in invent_lines:
invent_lines[key] += line.product_qty
else:
invent_lines[key] = line.product_qty
new_invent = invent_obj.create(cr, uid, {
'name': 'Merged inventory'
}, context=context)
for key, quantity in invent_lines.items():
invent_line_obj.create(cr, uid, {
'inventory_id': new_invent,
'location_id': key[0],
'product_id': key[1],
'product_uom_id': key[2],
'product_qty': quantity,
})
return {'type': 'ir.actions.act_window_close'}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,30 +0,0 @@
<?xml version="1.0"?>
<openerp>
<data>
<record id="name_form" model="ir.ui.view">
<field name="name">stock.inventory.merge.form</field>
<field name="model">stock.inventory.merge</field>
<field name="arch" type="xml">
<form string="Merge Inventories" version="7.0">
<separator string="Merge Inventories" />
<label string="Do you want to merge theses inventories?"/>
<footer>
<button name="do_merge" string="Yes" type="object" icon="gtk-apply" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<act_window name="Merge inventories"
res_model="stock.inventory.merge"
src_model="stock.inventory"
view_mode="form"
multi="True"
target="new"
key2="client_action_multi"
id="action_view_stock_merge_inventories"/>
</data>
</openerp>

View File

@ -23,9 +23,11 @@ from openerp.osv import fields, osv
from openerp.tools.translate import _
import openerp.addons.decimal_precision as dp
class stock_move_consume(osv.osv_memory):
_name = "stock.move.consume"
_description = "Consume Products"
class stock_move_scrap(osv.osv_memory):
_name = "stock.move.scrap"
_description = "Scrap Products"
_columns = {
'product_id': fields.many2one('product.product', 'Product', required=True, select=True),
@ -35,59 +37,6 @@ class stock_move_consume(osv.osv_memory):
'restrict_lot_id': fields.many2one('stock.production.lot', 'Lot'),
}
#TOFIX: product_uom should not have differemt category of default UOM of product. Qty should be convert into UOM of original move line before going in consume and scrap
def default_get(self, cr, uid, fields, context=None):
""" Get default values
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for default value
@param context: A standard dictionary
@return: default values of fields
"""
if context is None:
context = {}
res = super(stock_move_consume, self).default_get(cr, uid, fields, context=context)
move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
if 'product_id' in fields:
res.update({'product_id': move.product_id.id})
if 'product_uom' in fields:
res.update({'product_uom': move.product_uom.id})
if 'product_qty' in fields:
res.update({'product_qty': move.product_qty})
if 'location_id' in fields:
res.update({'location_id': move.location_id.id})
return res
def do_move_consume(self, cr, uid, ids, context=None):
""" To move consumed products
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param ids: the ID or list of IDs if we want more than one
@param context: A standard dictionary
@return:
"""
if context is None:
context = {}
move_obj = self.pool.get('stock.move')
move_ids = context['active_ids']
for data in self.browse(cr, uid, ids, context=context):
move_obj.action_consume(cr, uid, move_ids,
data.product_qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id and data.restrict_lot_id.id or False,
context=context)
return {'type': 'ir.actions.act_window_close'}
class stock_move_scrap(osv.osv_memory):
_name = "stock.move.scrap"
_description = "Scrap Products"
_inherit = "stock.move.consume"
_defaults = {
'location_id': lambda *x: False
}
@ -103,8 +52,9 @@ class stock_move_scrap(osv.osv_memory):
"""
if context is None:
context = {}
res = super(stock_move_consume, self).default_get(cr, uid, fields, context=context)
res = super(stock_move_scrap, self).default_get(cr, uid, fields, context=context)
move = self.pool.get('stock.move').browse(cr, uid, context['active_id'], context=context)
location_obj = self.pool.get('stock.location')
scrap_location_id = location_obj.search(cr, uid, [('scrap_location','=',True)])
@ -139,7 +89,6 @@ class stock_move_scrap(osv.osv_memory):
return {'type': 'ir.actions.act_window_close'}
class split_in_production_lot(osv.osv_memory):
_name = "stock.move.split"
_description = "Split in Serial Numbers"

View File

@ -1,41 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Consume, scrap move -->
<record id="view_stock_move_consume_wizard" model="ir.ui.view">
<field name="name">Consume Move</field>
<field name="model">stock.move.consume</field>
<field name="arch" type="xml">
<form string="Consume Move" version="7.0">
<group string="Consume Products">
<field name="product_id" readonly="1"/>
<label for="product_qty"/>
<div>
<field name="product_qty" class="oe_inline"/>
<field name="product_uom" class="oe_inline" readonly="1" groups="product.group_uom"/>
</div>
<field name="restrict_lot_id" domain="[('product_id','=',product_id)]" groups="stock.group_tracking_lot"
context="{'default_product_id': product_id}"/>
<field name="location_id" groups="stock.group_locations"/>
</group>
<footer>
<button name="do_move_consume" string="Ok" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="move_consume" model="ir.actions.act_window">
<field name="name">Consume Move</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">stock.move.consume</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Scrap move -->
<record id="view_stock_move_scrap_wizard" model="ir.ui.view">
<field name="name">Scrap Move</field>