Improved stock computation behaviour

This commit is contained in:
Bertrand Chenal committed 2008-07-11 23:20:17 +02:00
1 parent c3a1dddec7
commit e6c6b15a1d
5 files changed
+93 -65

No files matched your search

+3 -3
View File
@@ -18,7 +18,7 @@ class Inventory(OSV):
location = fields.Many2One(
'stock.location', 'Location', required=True,
domain="[('type', '=', 'storage')]", states=STATES)
date = fields.Date('Date',)
date = fields.Date('Date')
lost_found = fields.Many2One(
'stock.location', 'Lost and Found', required=True,
domain="[('type', '=', 'lost_found')]", states=STATES)
@@ -188,9 +188,9 @@ class CompleteInventory(Wizard):
# Compute product quantities
if inventory.date:
context = context.copy()
context['forecast_date'] = inventory.date
context['stock_date'] = inventory.date
pbl = product_obj.products_by_location(
cursor, user, [inventory.location.id], forecast=True,
cursor, user, [inventory.location.id],
context=context)
else:
pbl = product_obj.products_by_location(
+15 -14
View File
@@ -2,6 +2,7 @@
"Wharehouse"
from trytond.osv import fields, OSV
from trytond.wizard import Wizard, WizardOSV
import datetime
STATES = {
'readonly': "not active",
@@ -86,14 +87,13 @@ class Location(OSV):
return dict([(i,0) for i in ids])
product_obj = self.pool.get('product.product')
all_ids = self.search(cursor, user, [('parent', 'child_of', ids)])
if name == 'forecast_quantity':
pbl = product_obj.products_by_location(
cursor, user, location_ids=all_ids,
product_ids=[context['product']], forecast=True, context=context)
else:
pbl = product_obj.products_by_location(
cursor, user, location_ids=all_ids,
product_ids=[context['product']], context=context)
if name != 'forecast_quantity' and context.get('stock_date'):
if context['stock_date'] != datetime.date.today():
context = context.copy()
del context['stock_date']
pbl = product_obj.products_by_location(
cursor, user, location_ids=all_ids,
product_ids=[context['product']], context=context)
qty_by_ltn = dict([(i['location'], i['quantity']) for i in pbl])
to_compute = dict.fromkeys(all_ids, True)
locations = self.browse(cursor, user, all_ids, context=context)
@@ -141,14 +141,14 @@ class Party(OSV):
Party()
class ChooseForecatsDateInit(WizardOSV):
_name = 'stock.location_forecast_date.init'
class ChooseStockDateInit(WizardOSV):
_name = 'stock.location_stock_date.init'
forecast_date = fields.Date(
'Forecast Date', help='Allow to compute expected '\
'stock quantities for this date.\n'\
'* An empty value is an infinite date in the future.\n'\
'* A date in the past will provide historical values.')
ChooseForecatsDateInit()
ChooseStockDateInit()
class OpenProduct(Wizard):
@@ -158,7 +158,7 @@ class OpenProduct(Wizard):
'init': {
'result': {
'type': 'form',
'object': 'stock.location_forecast_date.init',
'object': 'stock.location_stock_date.init',
'state': [
('end', 'Cancel', 'tryton-cancel'),
('open', 'Open', 'tryton-ok', True),
@@ -186,9 +186,10 @@ class OpenProduct(Wizard):
context=context)
res = act_window_obj.read(cursor, user, model_data.db_id, context=context)
context = {'locations': data['ids']}
if context == None: context = {}
context['locations'] = data['ids']
if data['form']['forecast_date']:
context['forecast_date'] = data['form']['forecast_date']
context['stock_date'] = data['form']['forecast_date']
res['context'] = str(context)
return res
+2 -2
View File
@@ -170,8 +170,8 @@
<field name="type">lost_found</field>
</record>
<record model="ir.ui.view" id="location_forecast_date_init_view_form">
<field name="model">stock.location_forecast_date.init</field>
<record model="ir.ui.view" id="location_stock_date_init_view_form">
<field name="model">stock.location_stock_date.init</field>
<field name="type">form</field>
<field name="arch" type="xml">
<![CDATA[
+71 -44
View File
@@ -20,14 +20,13 @@ class Product(OSV):
location_ids = self.pool.get('stock.location').search(
cursor, user, [('parent', 'child_of', context['locations'])],
context=context)
if name == 'forecast_quantity':
pbl = self.products_by_location(
cursor, user, location_ids=location_ids, product_ids=ids,
forecast=True, context=context)
else:
pbl = self.products_by_location(
cursor, user, location_ids=location_ids, product_ids=ids,
context=context)
if name != 'forecast_quantity' and context.get('stock_date'):
if context['stock_date'] != datetime.date.today():
context = context.copy()
context['stock_date'] = datetime.date.today()
pbl = self.products_by_location(
cursor, user, location_ids=location_ids, product_ids=ids,
context=context)
res = {}
for product_id in ids:
res[product_id] = 0.0
@@ -39,7 +38,7 @@ class Product(OSV):
res = True
for field, operator, operand in domain:
value = line.get(field)
if not value:
if value == None:
return False
if operator not in ("=", ">=", "<=", ">", "<", "!="):
return False
@@ -56,26 +55,32 @@ class Product(OSV):
context=context)
if name == 'forecast_quantity':
pbl = self.products_by_location(
cursor, user, location_ids=location_ids, forecast=True,
context=context)
cursor, user, location_ids=location_ids,
skip_zero=False, context=context)
for line in pbl:
line['forecast_quantity'] = line['quantity']
del line['quantity']
else:
if context.get('stock_date'):
if context['stock_date'] != datetime.date.today():
context = context.copy()
del context['stock_date']
pbl = self.products_by_location(
cursor, user, location_ids=location_ids, context=context)
cursor, user, location_ids=location_ids,
skip_zero=False, context=context)
res= [line['product'] for line in pbl \
if self._eval_domain(line, domain)]
return [('id', 'in', res)]
def raw_products_by_location(self, cursor, user, location_ids,
product_ids=None, forecast=False, context=None):
product_ids=None, context=None):
"""
Return a list like : [(location, product, uom, qty)] for each
location and product given as argument. Null qty are not
returned and the tuple (location, product,uom) is unique.
returned and the tuple (location, product,uom) is unique. The
key stock_date in context can be used to compute stock for
other date than today.
"""
if not location_ids:
return []
@@ -83,8 +88,8 @@ class Product(OSV):
rule_obj = self.pool.get('ir.rule')
move_query, move_val = rule_obj.domain_get(cursor, user, 'stock.move')
if forecast and not (context.get('forecast_date') and \
context['forecast_date'] < datetime.date.today()):
if context.get('stock_date') and \
context['stock_date'] > datetime.date.today():
in_states = ['done', 'assigned', 'draft']
out_states = ['done', 'assigned', 'draft']
else:
@@ -121,15 +126,15 @@ class Product(OSV):
",".join(["%s" for i in product_ids]) + ")"
where_vals += product_ids
if forecast and context.get('forecast_date'):
where_clause += ' AND ('\
'(effective_date IS NULL '\
'AND ( planned_date <= %s or planned_date IS NULL)) '\
'OR effective_date <= %s'\
')'
where_date = [context['forecast_date'],context['forecast_date']]
where_clause += ' AND ('\
'(effective_date IS NULL '\
'AND ( planned_date <= %s or planned_date IS NULL)) '\
'OR effective_date <= %s'\
')'
if context.get('stock_date'):
where_date = [context['stock_date'], context['stock_date']]
else:
where_date = []
where_date = [datetime.date.today(), datetime.date.today()]
cursor.execute(select_clause % (
",".join(["%s" for i in in_states]), where_clause,
",".join(["%s" for i in out_states]), where_clause),
@@ -139,8 +144,14 @@ class Product(OSV):
return cursor.fetchall()
def products_by_location(self, cursor, user, location_ids,
product_ids=None, forecast=False, context=None):
product_ids=None, skip_zero=True, context=None):
"""
Return a list like : [{location: 1, product: 1, uom: 1, qty:
2}] for each location and product given as argument. The key
stock_date in context can be used to compute stock for other
date than today. If skip_zero, list item with quantity equal
to zero are not returned.
"""
uom_obj = self.pool.get("product.uom")
product_obj = self.pool.get("product.product")
@@ -149,27 +160,42 @@ class Product(OSV):
if not product_ids:
product_ids = product_obj.search(cursor, user, [], context=context)
else:
product_ids = product_ids[:]
uom_ids = uom_obj.search(cursor, user, [], context=context)
uom_by_id = dict((x.id, x) for x in uom_obj.browse(
cursor, user, uom_ids, context=context))
default_uom = dict((x.id, x.default_uom) for x in product_obj.browse(
default_uom = dict((p.id, p.default_uom) for p in product_obj.browse(
cursor, user, product_ids, context=context))
res = {}
res_dict = {}
for line in self.raw_products_by_location(
cursor, user, location_ids, product_ids, forecast=forecast,
context=context):
cursor, user, location_ids, product_ids, context=context):
location, product, uom, quantity= line
key = (location, product, default_uom[product].id)
res.setdefault(key, 0.0)
res[key] += uom_obj.compute_qty(
cursor, user, uom_by_id[uom], quantity, default_uom[product],
context=context)
return [{'location': key[0],
'product':key[1],
res_dict.setdefault(key, 0.0)
res_dict[key] += uom_obj.compute_qty(
cursor, user, uom_by_id[uom], quantity,
default_uom[product], context=context)
# Remove seen products from product_ids
if key[1] in product_ids:
product_ids.remove(key[1])
res = [{'location': key[0],
'product': key[1],
'uom': key[2],
'quantity': val} for key, val in res.iteritems()]
'quantity': val} for key, val in res_dict.iteritems()]
# Complete result with missing products if asked
if not skip_zero:
for location_id in location_ids:
for product_id in product_ids:
res.append({'location': location_id,
'product': product_id,
'uom': default_uom[product_id].id,
'quantity': 0.0})
return res
def view_header_get(self, cursor, user, value, view_type='form',
context=None):
@@ -183,14 +209,14 @@ class Product(OSV):
Product()
class ChooseForecatsDateInit(WizardOSV):
_name = 'stock.product_forecast_date.init'
class ChooseStockDateInit(WizardOSV):
_name = 'stock.product_stock_date.init'
forecast_date = fields.Date(
'Forecast Date', help='Allow to compute expected '\
'stock quantities for this date.\n'\
'* An empty value is an infinite date in the future.\n'\
'* A date in the past will provide historical values.')
ChooseForecatsDateInit()
ChooseStockDateInit()
class OpenLocation(Wizard):
'Products by Locations'
@@ -199,7 +225,7 @@ class OpenLocation(Wizard):
'init': {
'result': {
'type': 'form',
'object': 'stock.product_forecast_date.init',
'object': 'stock.product_stock_date.init',
'state': [
('end', 'Cancel', 'tryton-cancel'),
('open', 'Open', 'tryton-ok', True),
@@ -227,9 +253,10 @@ class OpenLocation(Wizard):
context=context)
res = act_window_obj.read(cursor, user, model_data.db_id, context=context)
context = {'product': data['id']}
if context == None: context = {}
context['product'] = data['id']
if data['form']['forecast_date']:
context['forecast_date'] = data['form']['forecast_date']
context['stock_date'] = data['form']['forecast_date']
res['context'] = str(context)
return res
+2 -2
View File
@@ -57,8 +57,8 @@
<field name="action" ref="wizard_open_location"/>
</record>
<record model="ir.ui.view" id="product_forecast_date_init_view_form">
<field name="model">product_forecast_date.init</field>
<record model="ir.ui.view" id="product_stock_date_init_view_form">
<field name="model">product_stock_date.init</field>
<field name="type">form</field>
<field name="arch" type="xml">
<![CDATA[