[IMP] stock_reserve: add views, now able to reserve and release a move, added a default 'Reservation Stock' location

This commit is contained in:
Guewen Baconnier
2013-09-05 14:07:06 +02:00
parent 011c9c8ee9
commit e8a2363ea9
4 changed files with 186 additions and 62 deletions

View File

@@ -32,7 +32,7 @@ Stock Reserve
=============
Allows to create stock reservation on a product or a selection of
products. The reservations can be monitored and lifter on the product
products. The reservations can be monitored and lifted on the product
view. Each reservation can have a validity date, once reached, the
reservation is automatically lifted.
@@ -40,7 +40,9 @@ reservation is automatically lifted.
'depends': ['stock',
],
'demo': [],
'data': [],
'data': ['view/stock_reserve.xml',
'data/stock_data.xml',
],
'auto_install': False,
'test': [],
'installable': True,

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="stock_location_reservation" model="stock.location">
<field name="name">Reservation Stock</field>
<field name="location_id" ref="stock.stock_location_company"/>
</record>
</data>
</openerp>

View File

@@ -19,18 +19,12 @@
#
##############################################################################
from datetime import datetime
from openerp.osv import orm, fields
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DT_FMT
class stock_reservation(orm.Model):
""" Allow to reserve products.
A stock reservation is basically a stock move,
but the reservation is handled by this model using
a ``_inherits``.
"""
_name = 'stock.reservation'
_description = 'Stock Reservation'
@@ -38,39 +32,17 @@ class stock_reservation(orm.Model):
_columns = {
'move_id': fields.many2one('stock.move',
'Move',
readonly=True,
'Reservation Move',
required=True,
readonly=True,
ondelete='cascade',
select=1),
'date_validity': fields.datetime('Validity Date'),
}
def _prepare_reserve(self, cr, uid, product_id, quantity, location_id,
date_validity=None, context=None):
product_obj = self.pool.get('product.product')
product = product_obj.browse(cr, uid, product_id, context=context)
location_dest_id = self._get_reservation_location(
cr, uid, product_id, context=context)
vals = {'name': 'Reservation', # sequence?
'product_id': product_id,
'product_qty': quantity,
'product_uom': product.uom_id.id,
'location_id': location_id,
'location_dest_id': location_dest_id,
'price_unit': product.standard_price or 0.0,
}
if date_validity:
vals.update({'date_validity': date_validity,
'date': date_validity,
'date_expected': date_validity,
})
else:
today = datetime.now().strftime(DT_FMT)
vals.update({'date': today,
'date_expected': today,
})
return vals
_defaults = {
'type': 'internal',
}
def _get_reservation_location(self, cr, uid, product_id, context=None):
""" Returns the appropriate destination location to
@@ -78,42 +50,30 @@ class stock_reservation(orm.Model):
"""
return 1
def reserve(self, cr, uid, product_id, quantity, location_id,
date_validity=None, context=None):
""" Reserve a product.
def reserve(self, cr, uid, ids, context=None):
""" Confirm a reservation
The reservation is done using the default UOM of the product.
A date until which the product is reserved can be specified.
:param product_id: id of the product to reserve
:param quantity: quantity of products to reserve
:param location_id: source location for the reservation
:param date_validity: optional datetime until which the reservation
is valid
:returns: id of the ``stock.reservation`` created
"""
vals = self._prepare_reserve(cr, uid, product_id, quantity,
location_id,
date_validity=date_validity,
context=context)
reservation_id = self.create(cr, uid, vals, context=context)
move_id = self.read(cr, uid,
reservation_id,
['move_id'],
context=context,
load='_classic_write')['move_id']
move_obj = self.pool.get('stock.move')
move_obj.action_confirm(cr, uid, [move_id], context=context)
# TODO: if no quantity in the location, it will stay 'confirmed'
# after action_confirm(), how to handle that?
move_obj.action_assign(cr, uid, [move_id])
return reservation_id
reservations = self.browse(cr, uid, ids, context=context)
move_ids = [reserv.move_id.id for reserv in reservations]
move_obj.action_confirm(cr, uid, move_ids, context=context)
move_obj.force_assign(cr, uid, move_ids, context=context)
move_obj.action_done(cr, uid, move_ids, context=context)
return True
def release(self, cr, uid, ids, context=None):
""" Release a reservation """
return self.unlink(cr, uid, ids, context=context)
def create(self, cr, uid, vals, context=None):
# TODO
return super(stock_reservation, self).create(cr, uid, vals,
context=context)
def unlink(self, cr, uid, ids, context=None):
""" Release the reservation """
if isinstance(ids, (int, long)):
ids = [ids]
reservations = self.read(cr, uid, ids, ['move_id'],
@@ -121,4 +81,39 @@ class stock_reservation(orm.Model):
move_obj = self.pool.get('stock.move')
move_ids = [reserv['move_id'] for reserv in reservations]
move_obj.action_cancel(cr, uid, move_ids, context=context)
return super(stock_reservation, self).unlink(cr, uid, ids, context=context)
return super(stock_reservation, self).unlink(cr, uid, ids,
context=context)
def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False,
loc_dest_id=False, partner_id=False):
""" On change of product id, if finds UoM, UoS,
quantity and UoS quantity.
"""
move_obj = self.pool.get('stock.move')
if ids:
reserv = self.read(cr, uid, ids, ['move_id'], load='_classic_write')
move_ids = [rv['move_id'] for rv in reserv]
else:
move_ids = []
return move_obj.onchange_product_id(
cr, uid, move_ids, prod_id=prod_id, loc_id=loc_id,
loc_dest_id=loc_dest_id, partner_id=partner_id)
def onchange_move_type(self, cr, uid, ids, type, context=None):
""" On change of move type gives source and destination location.
"""
move_obj = self.pool.get('stock.move')
location_obj = self.pool.get('stock.location')
data_obj = self.pool.get('ir.model.data')
result = move_obj.onchange_move_type(cr, uid, ids, type,
context=context)
get_ref = data_obj.get_object_reference
try:
__, dest_location_id = get_ref(cr, uid, 'stock_reserve',
'stock_location_reservation')
location_obj.check_access_rule(cr, uid, [dest_location_id],
'read', context=context)
except (orm.except_orm, ValueError):
dest_location_id = False
result['value']['location_dest_id'] = dest_location_id
return result

View File

@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="view_stock_reservation_form" model="ir.ui.view">
<field name="name">stock.reservation.form</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<form string="Stock Reservations" version="7.0">
<header>
<button name="reserve" type="object"
string="Reserve"
class="oe_highlight"
states="draft"/>
<button name="release" type="object"
string="Release"
class="oe_highlight"
states="assigned,confirmed,done"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,confirm"/>
</header>
<sheet>
<group>
<group name="main_grp" string="Details">
<field name="product_id"
on_change="onchange_product_id(product_id, location_id, location_dest_id, False)"
/>
<label for="product_qty" />
<div>
<field name="product_qty"
class="oe_inline"/>
<field name="product_uom"
groups="product.group_uom" class="oe_inline"/>
</div>
<field name="date_validity" />
<field name="name"/>
<field name="company_id"
groups="base.group_multi_company"
widget="selection"/>
</group>
<group name="origin_grp" string="Origin">
<field name="type" readonly="1" invisible="1"
on_change="onchange_move_type(type)"/>
<field name="location_id" groups="stock.group_locations"/>
<field name="create_date" groups="base.group_no_one"/>
</group>
<group name="destination_grp" string="Destination">
<field name="location_dest_id"
groups="stock.group_locations"/>
<field name="date_expected"
attrs="{'invisible': [('state', '=', 'done')]}"/>
<field name="date" attrs="{'invisible': [('state', '!=', 'done')]}"/>
</group>
<group name="note" string="Notes">
<field name="note" nolabel="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_stock_reservation_tree" model="ir.ui.view">
<field name="name">stock.reservation.tree</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<tree string="Stock Reservations" version="7.0"
colors="blue:state == 'draft'" >
<field name="move_id" />
<field name="product_id" />
<field name="product_qty" />
<field name="product_uom" />
<field name="date_validity" />
<field name="state"/>
<button name="reserve" type="object"
string="Reserve"
icon="terp-gtk-jump-to-ltr"
states="draft"/>
</tree>
</field>
</record>
<record id="view_stock_reservation_search" model="ir.ui.view">
<field name="name">stock.reservation.search</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<search string="Stock Reservations" version="7.0">
<field name="move_id" />
<field name="product_id" />
<field name="state"/>
</search>
</field>
</record>
<record id="action_stock_reservation" model="ir.actions.act_window">
<field name="name">Stock Reservations</field>
<field name="res_model">stock.reservation</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_stock_reservation_tree"/>
<field name="search_view_id" ref="view_stock_reservation_search"/>
<field name="context">{}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a stock reservation.
</p><p>
This menu allow you to prepare and reserve some quantities
of products.
</p>
</field>
</record>
<menuitem action="action_stock_reservation"
id="menu_action_stock_reservation"
parent="stock.menu_stock_products_moves"
sequence="10"
groups="stock.group_locations"/>
</data>
</openerp>