Add weight to unit load.

This commit refs #781
This commit is contained in:
Sergio Morillo 2015-08-28 13:50:21 +02:00
parent b331ebbe80
commit e2d1d2b0b9
7 changed files with 131 additions and 35 deletions

View File

@ -2,6 +2,7 @@
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import PoolMeta
from trytond.pyson import Id
__all__ = ['Configuration']
@ -15,4 +16,4 @@ class Configuration:
fields.Many2One('ir.sequence', 'Load unit Sequence', required=True,
domain=[('code', '=', 'stock.unit_load'),
('name', '=', 'Unit load')])
)
)

View File

@ -3,7 +3,6 @@
copyright notices and license terms. -->
<tryton>
<data>
<!-- Configuration form -->
<record model="ir.ui.view" id="stock_configuration_view_form">
<field name="model">stock.configuration</field>
@ -37,6 +36,5 @@
<field name="field" search="[('model.model', '=', 'stock.configuration'), ('name', '=', 'unit_load_sequence')]"/>
<field name="value" eval="'ir.sequence,' + str(ref('sequence_unit_load'))"/>
</record>
</data>
</tryton>

View File

@ -4,9 +4,12 @@ from trytond.pool import PoolMeta
from trytond.model import fields
__all__ = ['Move']
__metaclass__ = PoolMeta
class Move:
__name__ = 'stock.move'
unit_load = fields.Many2One('stock.unit_load', 'Unit load', ondelete='RESTRICT', select=True)
unit_load = fields.Many2One('stock.unit_load', 'Unit load',
ondelete='RESTRICT', select=True)

View File

@ -11,6 +11,7 @@ Imports::
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> today = datetime.date.today()
>>> tomorrow = today + relativedelta(days=1)
Create database::
@ -73,13 +74,18 @@ Add moves::
>>> move = unit_load.moves.new()
>>> move.planned_date = today
>>> move.product = product
>>> move.quantity = 1
>>> move.quantity = Decimal(35)
>>> move.from_location = lost_found_loc
>>> move.to_location = storage_loc
>>> move.currency = company.currency
>>> unit_load.save()
>>> unit_load.state
u'draft'
>>> unit_load.moves[0].state
u'draft'
Check computed fields::
>>> unit_load.location.code
u'STO'
>>> len(unit_load.last_moves) == 1
@ -87,8 +93,13 @@ Add moves::
>>> unit_load.click('assign')
>>> unit_load.state
u'assigned'
>>> unit_load.moves[0].state
u'assigned'
>>> len(unit_load.ul_moves)
1
>>> unit_load.uom.rec_name
u'Unit'
>>> unit_load.save()
Move wizard::
@ -105,6 +116,10 @@ State error::
>>> unit_load.click('do')
>>> unit_load.state
u'done'
>>> unit_load.quantity
35.0
>>> unit_load.forecast_quantity
35.0
Location error::
@ -120,12 +135,12 @@ Date error::
Traceback (most recent call last):
...
UserError: ...
>>> move_ul.form.planned_date = today + relativedelta(days=1)
>>> move_ul.form.planned_date = tomorrow
>>> move_ul.execute('move_')
>>> unit_load.reload()
>>> unit_load.state
u'draft'
>>> len(unit_load.moves)
2
>>> unit_load.last_date == today + relativedelta(days=1)
>>> unit_load.last_date == tomorrow
True

View File

@ -18,7 +18,8 @@ class StockUnitLoadTestCase(ModuleTestCase):
def suite():
suite = trytond.tests.test_tryton.suite()
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(StockUnitLoadTestCase))
suite.addTests(doctest.DocFileSuite('scenario_stock_unit_load.rst',
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite(
'scenario_stock_unit_load.rst',
setUp=doctest_setup, tearDown=doctest_teardown, encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite

View File

@ -1,5 +1,6 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
import datetime
from sql import Literal, Null
from sql.aggregate import Max
from sql.conditionals import Coalesce
@ -9,6 +10,7 @@ from trytond.pyson import Id, Not, Eval, In, Bool, Or, Equal
from trytond.model import fields, ModelView, ModelSQL
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateTransition, StateView, Button
from trytond.modules.stock import StockMixin
__all__ = ['UnitLoad', 'UnitLoadMove', 'MoveUnitLoad',
'MoveUnitLoadStart']
@ -19,7 +21,7 @@ UL_STATES = {'readonly': Bool(Eval('moves', [0]))}
UL_DEPENDS = ['moves']
class UnitLoad(ModelView, ModelSQL):
class UnitLoad(ModelView, ModelSQL, StockMixin):
"""Unit load"""
__name__ = 'stock.unit_load'
_rec_name = 'code'
@ -30,9 +32,22 @@ class UnitLoad(ModelView, ModelSQL):
code_readonly = fields.Function(fields.Boolean('Code Readonly'),
'get_code_readonly')
code_length = fields.Integer('Code Length', select=True, readonly=True)
product = fields.Many2One('product.product', 'Product', select=True, required=True, ondelete='RESTRICT')
product = fields.Many2One('product.product', 'Product',
select=True, required=True,
ondelete='RESTRICT')
uom = fields.Function(fields.Many2One('product.uom', 'UOM'),
'on_change_with_uom')
uom_digits = fields.Function(fields.Integer('UOM Digits'),
'on_change_with_uom_digits')
quantity = fields.Function(fields.Float('Quantity'),
'get_quantity',
searcher='search_quantity')
forecast_quantity = fields.Function(fields.Float('Forecast Quantity'),
'get_quantity',
searcher='search_quantity')
moves = fields.One2Many('stock.move', 'unit_load', 'Moves', readonly=True)
location = fields.Function(fields.Many2One('stock.location', 'Location'),
location = fields.Function(fields.Many2One('stock.location', 'Location',
depends=['moves']),
'get_location')
last_date = fields.Function(fields.Date('Last date',
states={'readonly': Not(Equal(Eval('state'), 'draft'))},
@ -56,10 +71,11 @@ class UnitLoad(ModelView, ModelSQL):
def __setup__(cls):
super(UnitLoad, cls).__setup__()
cls._error_messages.update({
'wrong_move_location': ('Cannot move unit load "%s" to Location "%s". Check its movements.'),
'wrong_move_date': ('Cannot move unit load "%s" at date "%s" because later moves exist.'),
'wrong_state': ('Unit load "%s" must be in Done state before moving.'),
'state_origin': ('Cannot change state of UL "%s" due to its last moves come from "%s".')})
'missing_location': 'Cannot find current location of UL "%s" from its moves.',
'wrong_move_location': 'Cannot move unit load "%s" to Location "%s". Check its movements.',
'wrong_move_date': 'Cannot move unit load "%s" at date "%s" because later moves exist.',
'wrong_state': 'Unit load "%s" must be in Done state before moving.',
'state_origin': 'Cannot change state of UL "%s" due to its last moves come from "%s".'})
cls._buttons.update({
'move_try': {'icon': 'tryton-go-next',
'invisible': Eval('state') != 'done'},
@ -107,13 +123,40 @@ class UnitLoad(ModelView, ModelSQL):
super(UnitLoad, cls).write(*args)
@classmethod
def copy(cls, unit_load, default=None):
def copy(cls, uls, default=None):
if default is None:
default = {}
default = default.copy()
default['code'] = None
default['moves'] = None
return super(unit_load, cls).copy(unit_load, default=default)
return super(uls, cls).copy(uls, default=default)
@fields.depends('product')
def on_change_with_uom(self, name=None):
if self.product:
return self.product.default_uom.id
return None
@fields.depends('product')
def on_change_with_uom_digits(self, name=None):
if self.product:
return self.product.default_uom.digits
return 2
@classmethod
def get_quantity(cls, records, name):
location_ids = Transaction().context.get('locations')
if not location_ids:
location_ids = [r.location.id for r in records if r.location]
products = [r.product for r in records]
return cls._get_quantity(records, name, location_ids,
products=products,
grouping=('product', 'unit_load'))
@classmethod
def search_quantity(cls, name, domain=None):
location_ids = Transaction().context.get('locations')
return cls._search_quantity(name, location_ids, domain)
@classmethod
def get_location(cls, records, name=None):
@ -121,19 +164,42 @@ class UnitLoad(ModelView, ModelSQL):
@classmethod
def _get_location(cls, records):
pool = Pool()
Move = pool.get('stock.move')
record_ids = [r.id for r in records]
ul_products = {r.id: r.product.id for r in records}
location_ids = list(set([m.to_location.id for r in records for m in r.moves]))
locations = dict.fromkeys(record_ids, None)
product_ids = [r.product.id for r in records] or None
context = Transaction().context
res = {}
for record in records:
res.setdefault(record.id, None)
if not record.moves:
if not context.get('stock_date_max'):
context['stock_date_end'] = datetime.date.max
if 'forecast' not in context:
context['forecast'] = True
context['active_test'] = False
grouping_filter = (product_ids, record_ids)
grouping = ('product', 'unit_load')
with Transaction().set_context(context):
query = Move.compute_quantities_query(location_ids=location_ids,
with_childs=False,
grouping=grouping,
grouping_filter=grouping_filter)
if query is None:
return {}
quantities = Move.compute_quantities(query, location_ids,
with_childs=False,
grouping=grouping,
grouping_filter=grouping_filter)
for key, quantity in quantities.iteritems():
if quantity <= 0:
continue
at_date = (context['stock_date_max'] if context.get('stock_date_max')
else max(m.effective_date or m.planned_date for m in record.moves
if m.state != 'cancel'))
moves = [m for m in record.moves if
(m.effective_date or m.planned_date) == at_date and m.state != 'cancel']
res[record.id] = moves[0].to_location.id
return res
if key[1] == ul_products[key[-1]]:
locations[key[-1]] = key[0]
return locations
def get_ul_moves(self, name=None):
pool = Pool()
@ -176,6 +242,8 @@ class UnitLoad(ModelView, ModelSQL):
to_create = []
for record in records:
from_location = record.location
if not from_location:
cls.raise_user_error('missing_location', record.rec_name)
if record.state != 'done':
cls.raise_user_error('wrong_state', record.rec_name)
if to_location.id == from_location.id:
@ -191,12 +259,15 @@ class UnitLoad(ModelView, ModelSQL):
to_create.extend(new_moves)
if to_create:
Move.save(to_create)
return to_create
return Move.browse(map(int, to_create))
def get_state(self, name=None):
pool = Pool()
Move = pool.get('stock.move')
if self.last_moves:
return self.last_moves[0].state
return 'draft'
return Move.default_state()
@classmethod
def search_state(cls, name, clause):
@ -305,9 +376,14 @@ class UnitLoadMove(ModelSQL, ModelView):
def table_query():
pool = Pool()
Move = pool.get('stock.move')
UL = pool.get('stock.unit_load')
move = Move.__table__()
ul_id = Transaction().context.get('unit_load')
ul = UL(ul_id)
where_clause = Literal(True)
if getattr(ul, 'product', None):
where_clause &= (move.product == ul.product.id)
date_column = Coalesce(move.effective_date, move.planned_date
).as_('date')
return move.select(
@ -322,7 +398,8 @@ class UnitLoadMove(ModelSQL, ModelView):
Literal(None).as_('write_date'),
date_column,
where=(move.unit_load == ul_id)
& (Coalesce(move.effective_date, move.planned_date) != Null),
& (Coalesce(move.effective_date, move.planned_date) != Null)
& where_clause,
group_by=(date_column, move.unit_load, move.state, move.from_location, move.to_location))

View File

@ -8,12 +8,13 @@
<field name="product"/>
<newline />
<notebook>
<page id="general" string="General">
<page id="general" string="General" col="6">
<label name="location"/>
<field name="location"/>
<label name="last_date"/>
<field name="last_date"/>
<field name="ul_moves" colspan="4"/>
<newline/>
<field name="ul_moves" colspan="6"/>
</page>
<page id="moves" string="Product moves">
<field name="moves" colspan="4"/>